在 Java 的 I/O 体系里,java.io.OutputStreamWriter 类用于封装 OutputStream类 ,把基于字节的输出流转变为基于字符的 Writer。而且,它能封装 OutputStream 的任意子类。
若要向如 UTF-8 或 UTF-16 编码的文件写入字符,OutputStreamWriter 类将会很实用。你可以向OutputStreamWriter 写入字符(字符值),它会对这些字符进行正确编码,再将编码后的字节写入底层的 OutputStream。
Java 的 OutputStreamWriter 是 Writer 类的子类。所以,在任何需要 Writer 的地方都能使用它。
下面是一个简单的 Java OutputStreamWriter 示例:
package com.hxstrive.java_io; import java.io.FileOutputStream; import java.io.OutputStreamWriter; public class OutputStreamWriterExample { public static void main(String[] args) throws Exception { // 写出数据 try(OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream("output.txt"))){ outputStreamWriter.write("Hello World"); } } }
OutputStreamWriter 类还有其他构造函数,允许您指定字符集(如 ISO-Latin1、GBK、UTF-8、UTF-16 等),以便将写入的字符转换为写入底层 OutputStream 的字节。例如:
try(OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream("output.txt"), StandardCharsets.UTF_8)){ outputStreamWriter.write("Hello World"); }
上述示例,创建了一个 OutputStreamWriter,它将把写入的所有字符转换为 UTF-8 编码字符(每个字符由一个或多个字节组成),并将 UTF-8 编码字节写入底层的 OutputStream。
OutputStreamWriter 类的 write(int) 方法,将 int 的低 16 位作为一个字符写入 OutputStreamWriter 所连接的目标。例如:
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream("output.txt"), "UTF-8"); outputStreamWriter.write('A');
OutputStreamWriter 类还有一个 write(char[]) 方法,可将字符数组写入 OutputStreamWriter 所连接的目标。write(char[]) 方法返回实际写入 OutputStreamWriter 的字符数。例如:
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream("output.txt"), "UTF-8"); char[] chars = new char[]{'A','B','C','D','E'}; outputStreamWriter.write(chars);
注意,向 OutputStreamWriter 写入字符数组比一次写入一个字符要快。速度的提升可能非常明显,甚至可高达 10 倍或更多。因此,建议尽可能使用 write(char[]) 方法。
具体的速度提升取决于运行 Java 代码的计算机的底层操作系统和硬件、内存速度、硬盘速度和缓冲区大小、网卡速度和缓冲区大小等问题,以及 OutputStreamWriter 将数据发送到哪个目的地(本地磁盘比网络连接更快)。
通过将 OutputStreamWriter 包装成 BufferedWriter,可以对写入 OutputStreamWriter 的字符进行透明缓冲。写入 BufferedWriter 的所有字节都将首先被缓冲到 BufferedWriter 的内部字符数组中。缓冲区满后,缓冲区会被一次性刷新到底层的 OutputStreamWriter 中。
public class BufferedWriter extends Writer { private Writer out; private char cb[]; private int nChars, nextChar; //... }
下面将创建一个 BufferedWriter:
Writer writer = new BufferedWriter( new OutputStreamWriter( new FileOutputStream("c:\\data\\output-file.txt"), "UTF-8"), 8192);
另一种为写入 OutputStreamWriter 的字符添加透明缓冲的方法是,先将 OutputStream 封装为 BufferedOutputStream,然后再将其封装为 OutputStreamWriter。
写入 BufferedOutputStream 的所有字节都将首先在 BufferedOutputStream 的内部字节数组中得到缓冲。当缓冲区满时,缓冲区会被一次性刷新到底层的 OutputStream 中。例如:
OutputStreamWriter outputStreamWriter = new OutputStreamWriter( new BufferedOutputStream( new FileOutputStream("c:\\data\\output-file.txt"), 8192), "UTF-8");
OutputStreamWriter 的 flush() 方法会将写入 OutputStreamWriter 的所有数据刷新到底层数据目标。例如,如果 OutputStreamWriter 是 FileWriter,那么写入 FileWriter 的字节可能尚未完全写入磁盘。即使您的 Java 代码已将数据写入 FileWriter,数据也可能在操作系统内存的某个地方缓冲。
通过调用 flush(),你可以确保任何缓冲数据都将被刷新(写入)到磁盘(或网络,或 OutputStreamWriter 的其他目标)。例如:
outputStreamWriter.flush();
当完成向 OutputStreamWriter 写入字符后,记得关闭它。关闭 OutputStreamWriter 也会关闭 OutputStreamWriter 正在写入的 OutputStream 实例。
关闭 OutputStreamWriter 仅需要调用它的 close() 方法,如下:
outputStreamWriter.close();
甚至,你还可以使用 Java7 中引入的 try-with-resources 结构。例如:
OutputStream output = new FileOutputStream("data/data.bin"); try(OutputStreamWriter outputStreamWriter = new OutputStreamWriter(output)){ Person person = new Person(); person.name = "Tom"; person.age = 34; outputStreamWriter.writeObject(person); }
注意,上述示例没有任何明确调用 close() 方法,调用 close() 方法由 try-with-resources 负责。
还需注意,第一个 FileOutputStream 实例并没有在 try-with-resources 代码块中创建。这意味着 try-with-resources 代码块不会自动关闭 FileOutputStream 实例。不过,当 OutputStreamWriter 关闭时,它也会关闭它所写入的 OutputStream 实例,因此 FileOutputStream 实例会在 OutputStreamWriter 关闭时被关闭。