30

我不明白这两个类之间的区别。你什么时候用一个而不是一个?我知道 FileWriter 可以将字符输出到文件,但据我所知,OutputStreamWriter 也可以。这是我测试过的一些代码,它们似乎工作相同,我没有添加异常处理的东西,但让我们假设它在那里。

FileWriter writer = new FileWriter("C:\\Users\\owner\\Desktop\\demo.txt");
writer.write("hello");
writer.close();

我也试过这段代码:

File file = new File("C:\\Users\\owner\\Desktop\\demo.txt");
os = new OutputStreamWriter(new FileOutputStream(file));
os.write("hello");
os.close();

这两个对我来说似乎都一样。唯一发生奇怪的事情是当我尝试在 write() 方法中放入一个 int 值。对于 FileWriter 示例,我的 demo.txt 完全是空的。对于 OutputStreamWriter 示例,我的文本文件中有一些奇怪的符号。我正在阅读一本 java 书,我对 OutputStreamWriter 的唯一解释是它“将字符流转换为字节流”,所以我不应该在第二个示例中看到我的文本文件中的一些字节吗?

一些澄清将不胜感激。

4

4 回答 4

51

XXXInputStream 和 XXXOutputStream(其中 XXX 不同,有很多选项)处理 8 位字节。例如,OutputStream.write(byte[] c);

XXXWriter 或 XXXReader 处理 16 位字符。例如,Reader.read(char[] cbuf)

OutputStreamWriter 将 OutputStream 转换为 Writer。您可能已经猜到了,InputStreamReader 从 InputStream 转换为 Reader。我不知道有任何相反的类,即将 Reader 转换为 InputStream。

FileWriter 是一个与文件对话的 Writer。由于 Java 字符串在内部使用字符(16 位,因此它们可以处理 Unicode),因此 FileWriter 是与 Unicode 字符串一起使用的自然类。

FileOutputStream 是用于将字节写入文件的 OutputStream。OutputStreams 不接受字符(或字符串)。通过将它包装在一个 OutputStreamWriter 中,您现在有了一个接受字符串的 Writer。

现在,真正的问题是,您何时使用 Reader/Writer 以及何时使用 Stream?我已经使用 Java 多年,有时我也会感到困惑。我相信以下是正确的:

便捷指南 - 如何决定使用哪个:

  1. 如果您正在处理二进制数据(例如图像),请使用 Streams。
  2. 如果您使用非 ASCII Unicode 字符,例如中文,请使用 Readers/Writers。
  3. 如果您使用普通的 ASCII 文本(传统的 0-127 字符),您可以(通常)使用其中任何一个。

其他一些链接:

Java IO 中的输入流和阅读器

InputStream 与 InputStreamReader

于 2012-07-07T00:33:46.627 回答
14

实际上本身没有区别,FileWriter只是一个便利类。它扩展OutputStreamWriter并创建了自己需要的FileOutputStream东西。

关于write(int):该方法将具有指定代码点的单个字符写入流,它不会写入数值的文本表示。

至于空文件,请注意,当您希望将写入的内容刷新到底层存储(无论是文件还是网络流或您能想到的任何东西)时,您应该始终刷新缓冲区。只需os.flush()在写完后调用,就可以了。
编辑:正如 Thilo 正确提到的,关闭流应该已经刷新它(以及所有底层流)。

最后但并非最不重要的一点是,您几乎总是应该明确指定您希望写入器写入的字符集/编码。写入器写入字符,而 OutputStreams 写入字节,因此您必须指定如何将这些字符编码为字节。如果您不指定编码,则使用系统默认值,这可能不是您想要的。

于 2012-07-07T00:17:33.253 回答
3

这是从这里

在 java.io 中,您可以执行字节 IO 或字符 IO。字节 IO 可用于任何形式的数据,而无需对该数据表示的任何解释。字符 IO 用于表示为字符序列的信息。

对于字节 IO,我们有各种类型的 InputStream/OutputStream 类,例如示例 1) 中的 FileOutputStream。对于具有各种形式的 Reader/Writer 类的字符数据,例如您的示例中的 FileWriter。在这两种情况下都可以进行缓冲,因此有 BufferedWriter 和 BufferedOutputStream 类。

要执行字符 IO 字符,有时必须使用某种形式的编码将其转换为字节数据。FileWriter 会为您执行此操作,这就是为什么它有一个构造函数,该构造函数将编码与文件名一起使用。常见的编码包括 UTF-8、UTF-16 和 US-ASCII。

OutputStreamWriter 是一个只对字符进行编码的类。这就是为什么它是一个 Writer 并且它的构造函数将一个 OutputStream 作为参数和一个可选的编码参数。

如果您省略显式编码规范,FileWriter 和 ByteArrayOutputStream 都将使用您平台的默认编码。这是需要非常小心的事情,因为它在不同的 JVM 之间会有所不同。

于 2012-07-07T00:21:16.527 回答
2

如果要更改编码,请使用 OutputStreamWriter 而不是 FileOutputStream。FileOutputStream 是用于编写字符文件的方便类。它使用默认编码。

强制编码为 UTF-8,如下所示:

OutputStreamWriter osw = new OutputStreamWriter(
    new FileOutputStream(exportPath),
    Charset.forName("UTF-8").newEncoder() 
);
于 2012-08-06T13:27:53.997 回答