1 背景
字符文件是很普遍的文件类型,如txt文件,ini文件等,对字符文件的操作是Java IO很基础也很重要的一部分。字符文件的读写分别用到FileReader和FileWriter两个类,下面分别从这两个类出发,掌握Java IO对字符文件的操作原理和流程。
2 读操作
2.1 FileReader类
FileReader类是读取字符文件的核心类,该类的类签名为:public class FileReader extends InputStreamReader
其中InputStreamReader是转换读取流(后面会详细介绍),继承自Java IO的读取流基类Reader
FileReader类拥有三个重载的构造函数,其中最常用的一个构造函数如下:
public FileReader(String fileName) throws FileNotFoundException {
super(new FileInputStream(fileName));
}
可以看到其调用了其父类(InputStreamReader类)的构造函数,并且传入了字节流对象(FileInputStream)为参数,因此其实现的原理是利用底层字节流实现的
2.2 读取字符文件
FileReader类读取字符文件主要依靠的是一些列的read方法,而这些方法是字符读取流基类Reader类的方法,而并不是FileReader类自己实现的。而读取字符文件可以一次读一个字符或者一次读一个字符数组,其中前者的实现原理是读一个长度为1的字符数组,而一次读一个字符数组的代码如下:
import java.io.FileReader;
import java.io.IOException;
/**
* Created by fubinhe on 16/10/17.
*/
public class FileReaderWriter {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("1.txt");
char[] buf = new char[1024];
int len;
while ((len = fr.read(buf)) != -1) {
System.out.println(new String(buf, 0, len));
}
fr.close();
}
}
其中,read方法返回一个int型结果,这个结果表示读取到的字符数组的长度,当这个值为-1时表示读到了字符文件的结尾。
2.3 异常处理
上面的代码可以实现将字符文件中的所有字符全部读出来,但是没有处理异常。在Java IO中绝大部分的异常都是IOException,在上述代码中,有三处会可能产生异常,第一处为FileReader对象的构造函数,read函数和close函数。完善的异常处理程序如下:
import java.io.FileReader;
import java.io.IOException;
/**
* Created by fubinhe on 16/10/17.
*/
public class FileReaderWriter {
public static void main(String[] args) {
FileReader fr = null;
try {
fr = new FileReader("1.txt");
char[] buf = new char[1024];
int len;
while ((len = fr.read(buf)) != -1) {
System.out.println(new String(buf, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fr != null) {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
在上面代码中,需要注意以下两点:
(1)在catch代码块中,只是将异常信息打印处理了,而在实际中可以有更复杂的操作,比如抛出一个RuntimeException,终止程序
(2)close方法是一定要执行的,所以在finally代码块中,而执行close函数时要判断FileReader引用是否为空(因为如果文件不存在则FileReader引用为空),并且在执行close函数时也要处理异常
3 写操作
3.1 FileWriter类
FileWriter类是希尔字符文件的核心类,该类的类签名为:public class FileWriter extends OutputStreamWriter
其父类OutputStreamWriter为转换写入流,继承自字符读取流的基类Writer
该类有一系列的构造函数,主要分为两类,即在原有文件的基础上追加写入和重新写入
3.2 写入字符文件
FileWriter类写入字符文件主要依靠的是一些列的write方法,可以向文件中一次写一个字符,一个字符数组,一个字符串,通常向文件中写入字符串的代码如下:
import java.io.FileWriter;
import java.io.IOException;
/**
* Created by fubinhe on 16/10/17.
*/
public class FileReaderWriter {
public static void main(String[] args) {
FileWriter fw = null;
try {
fw = new FileWriter("1.txt");
fw.write("123\n");
fw.write("sfdfd\n");
//fw.flush(); // 将内容刷新到文件中
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fw != null) {
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
在上述代码中,需要注意以下两点:
(1)FileWriter对象写入一行数据比较费劲,需要手动加入换行符(在mac系统中即为'\n'),后面将要介绍的两个类BufferedReader和PrintWriter对换行符的处理更优雅
(2)调用FileWriter的write方法并没有将数据持久化到文件中,而是写入到了流中即内存中,如果想立即写入文件,可以调用flush函数,在关闭文件时会自动调用该函数
4 总结
综上所述,Java IO操作字符文件通常有以下的几点规律:
(1)通过给构造函数传入文件的路径可以方便的产生字符流对象(当然也可以传入一个File对象)
(2)注意对异常的处理流程,并且流在程序结束的时候一定要关闭以免造成资源浪费
(3)注意换行符的处理