文件输入输出流 FileInputStream 和 FileOutputStream 负责完成对本地磁盘文件的顺序输入输出操作。
【例 10-5】通过程序创建一个文件,从键盘输入字符,当遇到字符“#”时结束,在屏幕上显示该文件的所有内容。
1 【例 10-5】通过程序创建一个文件,从键盘输入字符,当遇到字符“#”时结束,在屏幕上显示该文件的所有内容。 2 //********** ep10_5.java ********** 3 import java.io.*; 4 class ep10_5{ 5 public static void main(String args[]){ 6 char ch; 7 int data; 8 try{ 9 FileInputStream a=new FileInputStream(FileDescriptor.in); //创建文件输入流对象 10 FileOutputStream b=new FileOutputStream("ep10_5"); //创建文件输出流对象 11 System.out.println("请输入字符,以#号结束:"); 12 while((ch=(char)a.read())!='#'){ 13 b.write(ch); 14 } 15 a.close(); 16 b.close(); 17 System.out.println(); 18 FileInputStream c=new FileInputStream("ep10_5"); 19 FileOutputStream d=new FileOutputStream(FileDescriptor.out); 20 while(c.available()>0){ 21 data=c.read(); 22 d.write(data); 23 } 24 c.close();d.close(); 25 } 26 catch(FileNotFoundException e){ 27 System.out.println("找不到该文件!"); 28 } 29 catch(IOException e){} 30 } 31 }
运行后在程序目录建立一个名称为 ep10_5 的文件,运行结果如图 10-8 所示:
图 10-8 例 10_5 运行结果
FileDescriptor 是 java.io 中的一个类,该类不能实例化,其中包含三个静态成员:in、out 和err,分别对应于标准输入流、标准输出流和标准错误流,利用它们可以在标准输入输出流上建立文件输入输出流,实现键盘输入或屏幕输出操作。
【例 10-6】实现对二进制图形文件(.gif)的备份。
1 【例 10-6】实现对二进制图形文件(.gif)的备份。 2 //********** ep10_6.java ********** 3 import java.io.*; 4 class ep10_6{ 5 public static void main(String args[]) throws IOException{ 6 FileInputStream a=new FileInputStream("ep10_6.gif"); 7 FileOutputStream b=new FileOutputStream("ep10_6_a.gif"); 8 System.out.println("文件的大小为:"+a.available()); 9 byte c[]=new byte[a.available()]; 10 a.read(c); //将图形文件读入数组 11 b.write(c); //将数组中的数据写入到新文件中 12 System.out.println("文件已经被更名复制!"); 13 a.close(); 14 b.close(); 15 } 16 }
运行后在程序目录备份了一个名称为 ep10_6_a.gif 的文件,运行结果如图 10-9 所示:
图 10-9 例 10_6 运行结果
FilterInputStream 和 FileOutputStream 是 InputStream 和 OutputStream 的直接子类,分别实现了在数据的读、写操作的同时能对所传输的数据做指定类型或格式的转换,即可实现对二进制字节数据的理解和编码转换。
常用的两个过滤流是数据输入流 DataInputStream 和数据输出流 DataOutputStream。其构造方法为:
DataInputStream(InputStream in); //创建新输入流,从指定的输入流 in 读数据
DataOutputStream(OutputStream out); //创建新输出流,向指定的输出流 out 写数据
由于 DataInputStream 和 DataOutputStream 分别实现了 DataInput 和 DataOutput 两个接口(这两个接口规定了基本类型数据的输入输出方法)中定义的独立于具体机器的带格式的读写操作,从而实现了对不同类型数据的读写。由构造方法可以看出,输入输出流分别作为数据输入输出流的构造方法参数,即作为过滤流必须与相应的数据流相连。
DataInputStream 和 DataOutputStream 类提供了很多个针对不同类型数据的读写方法,具体内容读者可参看 Java 的帮助文档。
【例 10-7】将三个 int 型数字 100,0,-100 写入数据文件 ep10_6.dat 中。
1 【例 10-7】将三个 int 型数字 100,0,-100 写入数据文件 ep10_6.dat 中。 2 //********** ep10_7.java ********** 3 import java.io.*; 4 class ep10_7{ 5 public static void main(String args[]){ 6 String fileName="ep10_7.dat"; 7 int value1=100,value2=0,value3=-100; 8 try{ 9 //将 DataOutputStream 与 FileOutputStream 连接输出不同类型的数据 10 DataOutputStream a=new DataOutputStream(new FileOutputStream(fileName)); 11 a.writeInt(value1); 12 a.writeInt(value2); 13 a.writeInt(value3); 14 a.close(); 15 } 16 catch(IOException i){ 17 System.out.println("出现错误!"+fileName); 18 } 19 } 20 }
运行后在程序目录中生成数据文件 ep10_7.dat,用文本编辑器打开后发现内容为二进制的:
00 00 00 64 00 00 00 00 FF FF FF 9C。
【例 10-8】读取数据文件 ep10_6.dat 中的三个 int 型数字,求和并显示。
1 【例 10-8】读取数据文件 ep10_6.dat 中的三个 int 型数字,求和并显示。 2 //********** ep10_8.java ********** 3 import java.io.*; 4 class ep10_8{ 5 public static void main(String args[]){ 6 String fileName="D://myjava/ep10_7.dat"; 7 int sum=0; 8 try{ 9 DataInputStream a=new DataInputStream(new BufferedInputStream(new FileInputStream(fileName))); 10 sum+=a.readInt(); 11 sum+=a.readInt(); 12 sum+=a.readInt(); 13 System.out.println("三个数的和为:"+sum); 14 a.close(); 15 } 16 catch(IOException e){ 17 System.out.println("出现错误!"+fileName); 18 } 19 } 20 }
运行结果:
三个数的和为:0
readInt 方法可以从输入输出流中读入 4 个字节并将其作为 int 型数据直接参与运算。由于已经知道文件中有 3 个数据,所以可以使用 3 个读入语句,但若只知道文件中是 int 型数据而不知道数据的个数时该怎么办呢?因为 DataInputStream 的读入操作如遇到文件结尾就会抛出 EOFException 异常,所以可将读操作放入 try 中。
1 try{ 2 while(true) 3 sum+=a.readInt(); 4 } 5 catch(EOFException e){ 6 System.out.pritnln("三个数的和为:"+sum); 7 a.close(); 8 }
EOFException 是 IOException 的子类,只有文件结束异常时才会被捕捉到,但如果没有读到文件结尾,在读取过程中出现异常就属于 IOException。
【例 10-9】从键盘输入一个整数,求该数的各位数字之和。
1 【例 10-9】从键盘输入一个整数,求该数的各位数字之和。 2 //********** ep10_9.java ********** 3 import java.io.*; 4 class ep10_9{ 5 public static void main(String args[]) throws IOException{ 6 DataInputStream a=new DataInputStream(System.in); 7 System.out.print("请输入一个整数:"); 8 int b=a.readInt(); 9 int sum=0; 10 int c=b; 11 while(c>0){ 12 int d=c%10; //取最低位 13 c=c/10; //去掉最低位 14 sum=sum+d; //累加各位之和 15 } 16 System.out.println(b+"的各位数字之和="+sum); 17 } 18 }
运行结果:
请输入一个整数:26
842403082 的各位数字之和=31
需要注意的是,输入的数据 26 为变成了 842403082,原因在于输入数据不符合基本类型数据的格式,从键盘提供的数据是字符的字节码表示方式,若输入 26,只代表 2 和 6 两个字符的字节数据,而不是代表整数 26 的字节码。
若要从键盘得到整数需要先读取字符串,再利用其他方法将字符串转化为整数。
System.in、System.out、System.err 这 3 个标准输入输流对象定义在 java.lang.System 包中,这 3 个对象在 Java 源程序编译时会被自动加载。
【例 10-10】输入一串字符显示出来,并显示 System.in 和 System.out 所属的类。
1 【例 10-10】输入一串字符显示出来,并显示 System.in 和 System.out 所属的类。 2 //********** ep10_10.java ********** 3 import java.io.*; 4 class ep10_10{ 5 public static void main(String args[]){ 6 try{ 7 byte a[]=new byte[128]; //设置输入缓冲区 8 System.out.print("请输入字符串:"); 9 int count =System.in.read(a); //读取标准输入输出流 10 System.out.println("输入的是:"); 11 for(int i=0;i<count;i++) 12 System.out.print(a[i]+""); //输出数组元素的 ASCII 值 13 System.out.println(); 14 for(int i=0;i<count-2;i++) //不显示回车和换行符 15 System.out.print((char)a[i]+""); //按字符方式输出元素 16 System.out.println(); 17 System.out.println("输入的字符个数为:"+count); 18 Class InClass=System.in.getClass(); 19 Class OutClass=System.out.getClass(); 20 System.out.println("in 所在的类为:"+InClass.toString()); 21 System.out.println("out 所在的类为:"+OutClass.toString()); 22 } 23 catch(IOException e){} 24 } 25 }
运行结果如图 10-10 所示:
图 10-10 例 10_10 运行结果
需要注意的是,输入了 3 个字符按回车后,输出的结果显示为 5 个字符。这是由于 Java 中回车被当作两个字符,一个是 ASCⅡ为 13 的回车符,一个是值为 10 的换行符。程序中 getClass()和 ToString()是 Object 类的方法,作用分别是返回当前对象所对应的类和返回当前对象的字符串表示。