读写文件,给人的初步印象是一个很简单的功能。然而在Java中,据说其数量超过数十种,初学者刚刚接触时肯定会产生许多困惑,包括笔者。现在我整理下读文件中所涉及到的基本类,以及一般
使用方法。本文参考Java 1.6 官方API文档。本次将整理下读取文件时的一些知识。首先会介绍一些使用的基础类,了解每个类的功能,以及各个类的继承关系,然后会对
他们的关系做出一些解释,最后会给出详细的代码以便模仿。不足之处敬请谅解。
类:
File类:
继承结构:
java.lang.Object
继承者 java.io.File
文件和目录路径名的抽象表示形式。关注的是文件在磁盘上的存储仅能代表一个文件或是目录的路径名而已。如果处理文件或者目录名,就应该使用 File 对象,而不是字符串。同时
理解在Java中,所有都是面向对象来处理的。
一般使用以下构造方法来实例化File对象:
File file = new File(pathname); //pathname为String类型
主要方法见API文档,在这里不做一一解释。
FileInputStream类:
继承结构:
java.lang.Object
继承者 java.io.InputStream
继承者 java.io.FileInputStream
继承自java.io.InputStream,从文件系统中的某个文件中获得输入字节流。以
二进制方式读取文件,与
编码无关,不存在
乱码问题。
一般使用以下构造方法来实例化,首先创建File对象,通过File对象来实例化FileInputStream。
File file = new File(pathname);
FileInputStream inputStream = new FileInputStream(file);
InputStreamReader 类:
是字节流通向字符流的桥梁,可以在
构造器重指定编码的方式,如果不指定的话将采用底层操作系统的默认编码方式,例如GBK等。其
构造函数需要流参数和编码方式。
继承结构:
java.lang.Object
继承者 java.io.Reader
继承者 java.io.InputStreamReader
FileReader 类:
用来读取字符文件的便捷类,继承自InputStreamReader。
实例化方法同FileInputStream,通过参数File对象来实例化:
FileReader fr = new FileReader(file);
继承结构:
java.lang.Object
继承者 java.io.Reader
继承者 java.io.InputStreamReader
继承者 java.io.FileReader
BufferedReader类:
继承自Reader类,提供通用的缓冲方式文本读取,缓冲能大幅提高I/O的性能。构造函数接收Reader类及其子类的参数。
继承结构:
java.lang.Object
继承者 java.io.Reader
继承者 java.io.BufferedReader
一些涉及到的抽象类:Reader和InputStream
Reader 用于读入16位字符,也就是 Unicode 编码的字符,这样可以包括汉字等字符;而 InputStream 用于读入 ASCII 字符和二进制数据。
InputStream的作用是标志那些从不同数据入口产生输入的类。这些数据入口包括文件、管道、Socket等,每个都有一个相关的InputStream子类。
Reader用于读取字符流的抽象类。子类涉及到上述的BufferedReader、FileReader、InputStreamReader。子类必须实现的方法只有 read(char[], int, int) 和 close()。
下面给出我画的一幅图直观说明类之间的关系以及构造函数所需要的参数。箭头标示该类作为所指示类构造函数的参数。
一些学习心得:
FileInputStream 类关注的是文件内容,以字节方式读取,而 File 类关注的是文件在磁盘上的存储。
FileReader与FileInputStream 的根本区别:
Reader及其子类提供的是字节流的读取,char型,16位,unicode编码。InputStream及其子类提供字节流的读取,byte型,8位。所以,FileReader 用于读取字符流。要读取原始字节流,请考虑使用 FileInputStream。用FileReader读取出来的是char数组或者String ,而使用FileInputStream读取出来的是byte数组。如果处理纯文本,则建议使用FileReader,适合阅读,但有时需要注意编码问题。其他情况,比如要读取视频文件、音乐文件,只能选择FileInputStream。网络间,如使用
socket使用Stream流。
FileReader与InputStreamReader:
FileReader继承自InputStreamReader,主要不同在于构造函数。InputStreamReader的构造函数参数为InputStream和编码方式,当指定编码方式时,需要使用InputStreamReader类。而FileReader的构造函数参数为File对象,或表示文件路径的String。
BufferedReader类的使用:
继承自Reader类,提供通用的缓冲方式文本读取。而且提供了很实用的readLine,读取分行文本很适合,BufferedReader是针对Reader的,不直接针对文件,也不是只针对文件读取。Reader 所作的每个读取请求都会导致对底层字符或字节流进行相应的读取请求。因此,建议用BufferedReader进行包装, 缓冲能大幅提高I/O的性能。如:
BufferedReader in = new BufferedReader(new FileReader("foo.in"));
将缓冲指定文件的输入。如果没有缓冲,则每次调用 read() 或 readLine() 都会导致从文件中读取字节,并将其转换为字符后返回,而这是极其低效的。
通常使用的规范用法:
1)从hello.txt中读取字节流。
File file = new File ("hello.txt");
FileInputStream in=new FileInputStream(file);
2)从hello.txt中读取字符,使用BufferReader提高其性能。
File file = new File ("hello.txt");
FileInputStream in=new FileInputStream(file);
InputStreamReader inReader=new InputStreamReader(in);
BufferedReader bufReader=new BufferedReader(inReader);
或者使用如下方法:
File file = new File ("hello.txt");
BufferedReader bufReader =
new BufferedReader(new InputStreamReader(new FileInputStream(file)));
这种方法清晰地显示每个类对应的关系,有助于理解。
3) File file = new File ("hello.txt");
FileReader fileReader=new FileReader(file);
BufferedReader bufReader=new BufferedReader(fileReader);
根据不同的用途以及对性能的不同需求,选择不同的方法。
另外FileInputStream(file)会抛出NotFileFoundException
异常,一般使用try catch。