Java面向字节流的应用

    |     2015年4月17日   |   输入输出(IO)操作   |     0 条评论   |    1604

面向字节流时,最常用的是文件字节流:FileInputStream / FileOutputStream,按顺序读写本地磁盘文件。再往上套过滤流,就能按基本类型写二进制;最外层则是 System.in / System.out / System.err 三套标准流。

下面几个例子都在教材编号 10-5 到 10-10 的范围内,从建文件、拷贝 gif,到 Data 流读写 int,再到键盘字节。

一、文件输入输出流

【例 10-5】程序创建一个文件,从键盘读字符,遇到 # 结束,再把文件内容打到屏幕上:

import java.io.*;

class ep10_5{

    public static void main(String args[]){

        char ch;

        int data;

        try{

            FileInputStream a=new FileInputStream(FileDescriptor.in);  //创建文件输入流对象

            FileOutputStream b=new FileOutputStream("ep10_5");  //创建文件输出流对象

            System.out.println("请输入字符,以#号结束:");

            while((ch=(char)a.read())!='#'){

                b.write(ch);

            }

            a.close();

            b.close();

            System.out.println();

            FileInputStream c=new FileInputStream("ep10_5");

            FileOutputStream d=new FileOutputStream(FileDescriptor.out);

            while(c.available()>0){

               data=c.read();

               d.write(data);

           }

           c.close();d.close();

       }

       catch(FileNotFoundException e){

          System.out.println("找不到该文件!");

       }

       catch(IOException e){}

    }

}

FileDescriptor 在 java.io 中,不能实例化,提供三个静态成员:in、out、err,对应标准输入、标准输出、标准错误。用它们可以在标准流上再包一层文件流,实现键盘输入或屏幕输出。

【例 10-6】备份二进制图形文件(.gif):一次 available() 得到长度,读进 byte 数组再写出。

import java.io.*;

class ep10_6{

    public static void main(String args[]) throws IOException{

        FileInputStream a=new FileInputStream("ep10_6.gif");

        FileOutputStream b=new FileOutputStream("ep10_6_a.gif");

        System.out.println("文件的大小为:"+a.available());

        byte c[]=new byte[a.available()];

        a.read(c);  //将图形文件读入数组

        b.write(c);  //将数组中的数据写入到新文件中

        System.out.println("文件已经被更名复制!");

        a.close();

        b.close();

    }

}

二、过滤流:DataInputStream / DataOutputStream

FilterInputStream 和 FilterOutputStream 是字节流的直接子类,读写的同时可做类型或格式转换,也就是理解二进制、做编码转换。(原文写成 FileOutputStream 作为过滤流父类,应为 FilterOutputStream。)

常用的两个过滤流是 DataInputStream 和 DataOutputStream:

  • DataInputStream(InputStream in):从指定输入流读数据。
  • DataOutputStream(OutputStream out):向指定输出流写数据。

它们分别实现 DataInput / DataOutput,按与机器无关的格式读写基本类型。构造时必须把另一条字节流传进去,过滤流不能单独存在。

【例 10-7】把三个 int:100、0、-100 写入 ep10_7.dat:

import java.io.*;

class ep10_7{

    public static void main(String args[]){

        String fileName="ep10_7.dat";

        int value1=100,value2=0,value3=-100;

        try{

            //将 DataOutputStream 与 FileOutputStream 连接输出不同类型的数据

            DataOutputStream a=new DataOutputStream(new FileOutputStream(fileName));

            a.writeInt(value1);

            a.writeInt(value2);

            a.writeInt(value3);

            a.close();

        }

        catch(IOException i){

            System.out.println("出现错误!"+fileName);

        }

    }

}

用文本编辑器打开会看到二进制:00 00 00 64 00 00 00 00 FF FF FF 9C。

【例 10-8】读回这三个 int 并求和(100 + 0 + (−100) = 0):

import java.io.*;

class ep10_8{

    public static void main(String args[]){

        String fileName="D:\\myjava/ep10_7.dat";

        int sum=0;

        try{

            DataInputStream a=new DataInputStream(new BufferedInputStream(new FileInputStream(fileName)));

            sum+=a.readInt();

            sum+=a.readInt();

            sum+=a.readInt();

            System.out.println("三个数的和为:"+sum);

            a.close();

        }

        catch(IOException e){

            System.out.println("出现错误!"+fileName);

        }

    }

}

运行结果:

三个数的和为:0

readInt() 从流里读 4 个字节当 int。已知正好 3 个数可以写 3 条读语句;若只知道是 int、不知道个数,读到文件尾会抛 EOFException,可把读循环放进 try:

import java.io.*;

class ep10_9{

    public static void main(String args[]) throws IOException{

        DataInputStream a=new DataInputStream(System.in);

        System.out.print("请输入一个整数:");

        int b=a.readInt();

        int sum=0;

        int c=b;

        while(c>0){

            int d=c%10;  //取最低位

            c=c/10;  //去掉最低位

            sum=sum+d;  //累加各位之和

        }

        System.out.println(b+"的各位数字之和="+sum);

    }

}

运行结果:

请输入一个整数:26

842403082 的各位数字之和=31

EOFException 是 IOException 的子类:只有碰到文件结束才会进这个 catch;读到一半出错仍是普通 IOException。

【例 10-9】从键盘读一个整数,求各位数字之和:

try{

    while(true)

    sum+=a.readInt();

}

catch(EOFException e){

    System.out.pritnln("三个数的和为:"+sum);

    a.close();

}

注意:输入 26,程序却可能打出 842403082 这类大数。因为 DataInputStream.readInt() 要的是 int 的四字节二进制,键盘送来的是字符 ‘2’、’6′ 的字节,并不是整数 26 的补码。要从键盘拿整数,应先读字符串再转换。

流 职责 注意
FileInput/OutputStream 顺序读写本地文件 例 10-5 / 10-6
DataInput/OutputStream 按基本类型读写二进制 必须包在另一条字节流上
System.in / out / err 标准输入、输出、错误 编译时自动加载

三、标准输入输出

System.in、System.out、System.err 定义在 java.lang.System,源程序编译时自动加载。

  • 标准输入 System.in 是 BufferedInputStream:read() 从键盘缓冲区读一字节,返回低位为该字节、高位为 0 的 int。
  • 标准输出 System.out 是 PrintStream(FilterOutputStream 子类),提供 print / println。
  • 标准错误 System.err 也是 PrintStream,专门把错误打到屏幕上,方便调试。

【例 10-10】输入一串字符并显示,同时打印 in、out 所属的类:

import java.io.*;

class ep10_10{

    public static void main(String args[]){

        try{

            byte a[]=new byte[128];  //设置输入缓冲区

            System.out.print("请输入字符串:");

            int count =System.in.read(a);  //读取标准输入输出流

            System.out.println("输入的是:");

            for(int i=0;i<count;i++)

               System.out.print(a[i]+"");  //输出数组元素的 ASCII 值

            System.out.println();

            for(int i=0;i<count-2;i++)  //不显示回车和换行符

                System.out.print((char)a[i]+"");  //按字符方式输出元素

            System.out.println();

            System.out.println("输入的字符个数为:"+count);

            Class InClass=System.in.getClass();

            Class OutClass=System.out.getClass();

            System.out.println("in 所在的类为:"+InClass.toString());

            System.out.println("out 所在的类为:"+OutClass.toString());

        }

        catch(IOException e){}

    }

}

输入 3 个字符再回车,计数常常是 5:Java 把回车当成两个字符(ASCII 13 的 CR 和 10 的 LF)。getClass() / toString() 来自 Object,分别返回运行时类和字符串表示。

一句话总结:字节流先落地文件,再用 Data 流按类型读写;键盘上的字符不是 int 的四字节,别拿 readInt 直接砸 System.in。

转载请注明来源:Java面向字节流的应用
本文链接地址:https://ai.zhousir.top/?p=260
回复 取消