学科分类
目录
Java基础

字节流读写文件

由于计算机中的数据基本都保存在硬盘的文件中,因此操作文件中的数据是一种很常见的操作。在操作文件时,最常见的就是从一个文件中读取数据并将数据写入到另一个文件,这一过程就是文件的读写。针对文件的读写操作,JDK专门提供了两个类,分别是FileInputStream和FileOutputStream。

FileInputStream是InputStream的子类,它是操作文件的字节输入流,专门用于读取文件中的数据。由于从文件读取数据是重复的操作,因此需要通过循环语句来实现数据的持续读取。

接下来通过一个案例来实现字节流对文件数据的读取。首先在Eclipse项目的根目录下创建一个文本文件test.txt,在文件中输入内容“hello”并保存;然后创建一个读取文本文件的类,具体代码如文件1所示。

文件1 Example01.java

 1    import java.io.*;
 2    public class Example01 {
 3        public static void main(String[] args) throws Exception {
 4            // 创建一个文件字节输入流来读取文件
 5            FileInputStream in = new FileInputStream("test.txt");
 6            // 定义一个int类型的变量b
 7            int b = 0;
 8            // 通过循环来读取文件,当返回值为-1结束循环
 9            while((b=in.read()) != -1){
 10                System.out.println(b); 
 11            }
 12            // 关闭流
 13            in.close();
 14        }
 15    }

运行结果如图1所示。

图1 运行结果

文件1中,创建的字节流对象FileInputStream通过read()方法将当前项目中的文件“test.txt”中的数据读取并打印。从图7-5中的运行结果可以看出,结果分别为104、101、108、108和111,这与test.txt文件中显示效果不太一样,这是因为读取到硬盘上的文件是以字节的形式存在的。在“test.txt”文件中,字符‘h’、‘e’、‘l’、‘l’、‘o’各占一个字节,因此,最终结果显示的是文件“test.txt”中的5个字节所对应的ASCII码值。

需要注意的是,在读取文件数据时,必须保证文件在相应目录存在并且是可读的,否则会抛出java.io.FileNotFoundException,即文件找不到的异常。如上述案例如果未在项目目录下创建文本文件“test.txt”,程序运行后,会出现图2所示的异常。

图2 运行结果

与FileInputStream对应的是FileOutputStream。FileOutputStream是OutputStream的子类,它是操作文件的字节输出流,专门用于把数据写入文件。接下来通过一个案例来演示如何将数据写入文件,如文件2所示。

文件2 Example02.java

 1    import java.io.*;
 1    public class Example02 {
 2        public static void main(String[] args) throws Exception {
 3            // 创建文件输出流对象,并指定输出文件名称
 4            FileOutputStream out = new FileOutputStream("out.txt");
 5            // 定义一个字符串
 6            String str = "hello";
 7            // 将字符串转换为字节数组进行写入操作
 8            out.write(str.getBytes());
 9            // 关闭流
 10            out.close();
 11        }
 12    }

程序运行后,会在项目当前根目录下生成一个新的文本文件out.txt(运行程序后,该文件可能不会立刻显示,此时使用鼠标右击项目,在弹出窗口中,单击“Refresh”,对项目进行刷新即可),打开此文件,会看到如图3所示的内容。

图3 out.txt

从图3可以看出,通过FileOutputStream写数据时,自动创建了文件out.txt,并将自定义的字符串内容写入到了目标文件。

需要注意的是,如果是通过FileOutputStream向一个已经存在的文件中写入数据,那么该文件中的数据首先会被清空,再写入新的数据。若希望在已存在的文件内容之后追加新内容,则可使用FileOutputStream的构造函数FileOutputStream(String fileName, boolean append)来创建文件输出流对象,并把append 参数的值设置为true。接下来通过一个案例来演示如何将数据追加到out.txt文件末尾,如文件3所示。

文件3 Example03.java

 1    import java.io.*;
 2    public class Example03 {
 3        public static void main(String[] args) throws Exception {
 4            // 创建文件输出流对象,并指定输出文件名称
 5            FileOutputStream out = new FileOutputStream("out.txt",true);
 6            // 定义一个字符串
 7            String str = " world";
 8            // 将字符串转换为字节数组进行写入操作
 9             out.write(str.getBytes());        
 10            out.close();
 11        }
 12    }

程序运行后,查看项目当前目录下的文件“out.txt”,如图4所示。

图4 out.txt

从图4可以看出,程序通过字节输出流对象向文件“out.txt”写入“ world”后,并没有将文件之前的数据清空,而是将新写入的数据追加到了文件的末尾。

由于I/O流在进行数据读写操作时会出现异常,为了代码的简洁,在上面的程序中使用了throws关键字将异常抛出,然而一旦遇到IO异常,I/O流的close()方法将无法执行,流对象所占用的系统资源将不能够释放。因此,为了保证I/O流的close()方法一定执行,通常会将关闭流的操作写在finally代码块中,具体代码如下所示:

finally{
    try{
        if(in!=null)              // 如果in不为空,关闭输入流 
            in.close();
    }catch(Exception e){
        e.printStackTrace();
    }
    try{
        if(out!=null)             // 如果out不为空,关闭输出流
            out.close();
    }catch(Exception e){
        e.printStackTrace();
    }
}
点击此处
隐藏目录