为了深入理解,需要先了解什么是字符流和字节流。那么让我们快速地了解一下——
字节流按字节访问文件。Java程序使用字节流执行8位字节的输入和输出。它适用于任何类型的文件,但不太适合文本文件。例如,如果文件使用Unicode编码,并且一个字符由两个字节表示,则字节流将分别处理这些字节,并且您需要自己进行转换。面向字节的流不使用任何编码方案,而面向字符的流使用字符编码方案(UNICODE)。所有字节流类都是从InputStream和OutputStream派生的。
字符流会按字符读取文件。字符流是比字节流更高级的概念。字符流实际上是一个已经包装了特定编码的逻辑以允许其输出字符的字节流。这意味着字符流需要提供文件的编码才能正常工作。字符流可以支持所有类型的字符集ASCII、Unicode、UTF-8、UTF-16等。所有字符流类都是从Reader和Writer派生的。
如果尝试读取使用默认java Unicode 8编码编写的.txt文件,则使用Reader和InputStream类读取文件将给出相同的输出。因为每个字节代表一个字符。
我创建了一些方法,将帮助您理解这两个术语之间的区别——"FileInputStream reads byte by byte"和"FileReader reads char by char"。请耐心阅读以下内容以便更好地理解。
现在您已经了解了这两种流的概念,让我们看一下示例,以了解它如何在内部工作——
使用Unicode 16编码写入文件中的一些数据的方法:
public void unicode16Writer() throws Exception {
try (OutputStream outputStream = new FileOutputStream("output.txt")) {
Writer writer = new OutputStreamWriter(outputStream, Charset.forName("UTF-16"));
writer.write("Hello World");
}
}
output.txt
Hello World
以下是从文件中读取数据的三种方式:第一种使用FileReader是默认方式,第二种使用FileInputStream,第三种使用带有Unicode-16字符集(编码)的InputStreamReader。
方法中的注释都是自说明的,请阅读以了解其工作原理。
FileReader
public void fileReaderUnicode8() throws IOException {
FileReader fr = new FileReader("output.txt");
int i;
int j = fr.read();
System.out.println("Output of FileReader using default cons(default charset) : " + (char) j);
}
输出
使用默认构造函数(FileReader)的输出,默认字符集: þ
文件输入流
public void readBytebyByte() throws IOException {
try (FileInputStream fis = new FileInputStream("output.txt")) {
int i;
int j = fis.read();
System.out.println("Output of FileInputStream reading byte by byte : " + (char) j);
}
}
输出
使用FileInputStream逐字节读取的输出:þ
InputStreamReader
public void unicode16Reader() throws IOException {
try (InputStream inputStream = new FileInputStream("output.txt")) {
Reader reader = new InputStreamReader(inputStream, Charset.forName("UTF-16"));
int data = reader.read();
System.out.println("uni-16 ISR: " + (char) data);
}
}
输出
uni-16中断服务例程:H