一、前言
既然字节流提供了能够处理任何类型数据的输入/输出操作的功能,那么为什么还存在字符流呢?我们来看一个例子
举例:通过字节流读取文本内容(含中文汉字)
public class Test { public static void main(String[] args) throws IOException { File file = new File("D:" + File.separator + "test.txt"); InputStream inputStream = new FileInputStream(file); int readByte = -2; while(readByte != -1){ if(readByte >= 0){ //将读取到的字节转成对应的字符 System.out.println((char)readByte); } readByte = inputStream.read(); } } }
结果:
ï
»
¿
h
e
l
l
o
ä
¸
å
½
w
o
r
l
d
æ
§
è
¡
说明:可以看到,hello world可以正常显示,汉字则成了乱码,这是因为字节流一次只能操作一个字节,而汉字是用两个字节的字符来表示的,所以字节流读取汉字的时候会将汉字截断,既然Java的口号就是"一次编写、处处运行",那么包含直接的字符输入/输出的支持是必要的。因此就有一些字符输入/输出流。
二、Reader和Writer
2.1 Reader是定义Java的字符输入流的抽象类,该类的所有方法在出错的情况下都将引发IOException。Reader类中有这些方法:
方 法 | 作 用 |
abstract void close() | 关闭该流并释放与之关联的所有资源 |
void mark(int readAheadLimit) | 标记流中的当前位置 |
boolean markSupported() | 判断此流是否支持mark()操作 |
int read() | 从文件中读取单个字符 |
int read(char[] cbuf) | 从文件中读取字符到cbuf |
abstract int read(char[] cbuf, int off, int len) | 将文件中的字符读入cbuf数组,从off位置开始,读取len个字符。三个read方法在字符可用、发生I/O异常或者已经到达流的末尾前,此方法会一直阻塞 |
int read(CharBuffer target) | 试图将文件中的字符读入指定的字符缓冲区 |
boolean ready() | 判断是否准备读取此流 |
voi reset() | 重置该流 |
long skip(long n) | 跳过n个字符 |
举例:说明一下前言中的例子用字符流来读的话
public class Test { public static void main(String[] args) throws IOException { File file = new File("D:" + File.separator + "test.txt"); Reader reader = new FileReader(file); int read = -2; while(read != -1){ read = reader.read(); if(read >= 0){ //将读取到的单个字符由int表示(in the range 0 to 65535)转成char System.out.println((char)read); } } } }
结果:
h
e
l
l
o
中
国
w
o
r
l
d
执
行
说明:可以看到,字符流读取含有汉字的文件,不会像字节流一样产生出乱码。
2.2 Writer是定义字符输出流的抽象类,所有该类的方法都返回一个void值并在出错的条件下引发IOException。Writer类中的方法有:
方 法 | 作 用 |
Writer append(char c) | 将制定字符添加到此writer |
Writer append(CharSequence csq) | 将制定字符序列添加到此writer |
Writer append(CharSequence csq, int start, int end) | 将指定字符序列的子序列添加到此writer.Appendable |
abstract void close() | 关闭此流,但要先flush()它 |
abstract void flush() | 刷新该流的缓冲 |
void write(char[] cbuf) | 将cbuf中的内容写入文件 |
abstract void write(char[] cbuf, int off, int len) | 将字符数组cbuf中从off开始的len个字节写入文件 |
void write(int c) | 写入单个字符到文件中 |
void write(String str) | 写入字符串到文件中 |
void write(String str, int off, int len) | 写入str从off位置开始的len个字符到文件中 |
2.3 FileReader和FileWriter
FileReader类创建了一个可以读取文件内容的Reader类,最常用的构造方法是:
1、FileReader(String fileName)
2、FileReader(File file)
FileWriter创建了一个可以写文件的Writer类,最常用的构造方法是:
1、FileWriter(String fileName)
2、FileWriter(String fileName, boolean append)
3、FileWriter(File file)
其中第二个构造方法,如果append为true,那么输出是追加到文件结尾的。FileWriter类的创建不依赖文件是否存在,在创建文件之前,FileWriter将在创建对象时打开它来作为输出。如果试图打开一个只读文件,那么将引发一个IOException。
举例:先写入文件,再从文件中读取,现在D盘目录下没有"readerAndWriter.txt":
public class Test { public static void main(String[] args) throws IOException { File file = new File("D:" + File.separator + "readerAndWriter.txt"); //创建字符输出流 Writer writer = new FileWriter(file); String content = "hello World 中国 center 执行"; //将内容写入文件 writer.write(content); //关闭输出流 writer.close(); //创建字符输入流 Reader reader = new FileReader(file); char[] chars = new char[1024]; //将文件的内容读取到chars数组中,并返回读取到的字符个数 int characterNumbers = reader.read(chars); if(characterNumbers == -1){ System.out.println("文件中无内容"); }else{ //输出读取到的内容 System.out.println(new String(chars)); } reader.close(); } }
结果:读取到写入文件的内容
hello World 中国 center 执行
这就是FileWriter和FileReader的使用,和FileOutputStream和FileInputStream的使用差不多,不过实际操作中一般不会用FileWriter和FileReader,这将在下一篇文章进行讲解。