适合读写文件的Java类是什么?

10

阅读一些有关Java文件I/O管理的资料,我知道了有不止一种输入和输出操作的选择。

它们分别是:

  • BufferedReaderBufferedWriter
  • FileReaderFileWriter
  • FileInputStreamFileOutputStream
  • InputStreamReaderOutputStreamWriter
  • Scanner

这些中哪一个是文本文件管理的最佳选择?序列化的最佳选择是什么?Java NIO 对此有何说法?


nio 简单地意味着 "新 I/O":https://en.wikipedia.org/wiki/New_I/O - Mark Whitaker
2
@MarkWhitaker 那个URL让我很感兴趣。这个页面比大多数维基页面深一个级别吗? - Cruncher
对于第一个问题,如果你正在使用大量数据,BufferedReader和writer会更好。 - Kakalokia
流(Stream)是用于二进制文件的。读取器(Reader)和写入器(Writer)则用于文本。 - user2793390
要在Java中进行最简单的文本文件IO操作,可以使用第三方库,例如[Guava](https://code.google.com/p/guava-libraries/)。请参见[相关问题中的此答案](https://dev59.com/jFTTa4cB1Zd3GeqPow5W#4909025)。 - Jonik
显示剩余2条评论
1个回答

20

两种数据

一般来说有两个“世界”:

  • 二进制数据
  • 文本数据

当它是一个文件(或套接字,或数据库中的BLOB等),那么它始终是二进制数据。

其中一些二进制数据可以被视为文本数据(这涉及到称为"编码"或"字符编码"的东西)。

二进制数据

每当您想处理二进制数据时,您需要使用InputStream/OutputStream类(通常,名称中包含Stream的所有内容)。

这就是为什么 Java 有 FileInputStreamFileOutputStream:它们可以读取和写入文件,并处理二进制数据。

文本数据

每当你需要处理 文本 数据时,你就需要使用 Reader/Writer 类。

每当你需要将二进制数据转换为文本(或者反之亦然),那么你就需要一些编码方式(常见的有 UTF-8、UTF-16、ISO-8859-1(及其相关编码方式)以及老式的 US-ASCII)。"幸运的是",Java 平台还有一种叫做 "默认平台编码" 的东西,当代码没有指定编码方式时,Java 就会使用它。

然而,默认平台编码方式也是一个双刃剑:

  • 它使编写代码更容易,因为您不必为每个操作指定编码但是
  • 它可能与您拥有的数据不匹配:如果平台默认编码为ISO-8859-1,而您读取的文件实际上是UTF-8,则会得到混乱的输出!

对于阅读,我们还应该提到BufferedReader,它可以包装在任何其他Reader周围,并添加处理整行的能力。

Scanner是一种特殊的类,旨在将文本输入解析为标记。它最适用于结构化文本,但通常用于System.in,以提供从stdin(即用户在键盘上输入的内容)读取数据的非常简单的方法。

弥合差距

现在,令人困惑的是,有些类可以在这些世界之间架起桥梁,它们的名称通常包含两部分

  • InputStreamReader 是一个消耗 InputStream读取器,本身是一个 Reader
  • OutputStreamWriter 是一个 Writer,用于向 OutputStream写入数据。

还有一些"快捷类",它们基本上结合了经常结合的两个其他类。

  • FileReader 基本上是一个 FileInputStreamInputStreamReader 的组合。
  • FileWriter 基本上是一个 FileOutputStreamOutputStreamWriter 的组合。

请注意,与更复杂的“手工构建”的选择相比,FileReaderFileWriter 存在一个主要缺点:它们始终使用平台默认编码,这可能不是您想要的!

序列化方面怎么样?

ObjectOutputStreamObjectInputStream是用于序列化的特殊流。

正如类名所示,序列化仅涉及二进制数据(即使是序列化String对象),因此您应该专门使用*Stream类。只要避免任何Reader/Writer类,您就应该没问题。

更多资源


谢谢,你能看到我的编辑并告诉我更改了什么吗? - diegoaguilar
@Diego:很抱歉,但是那会显著改变问题的范围,应该可能移动到一个单独的问题中。 - Joachim Sauer
到目前为止,我接受了你的答案。你说得对。只是我希望我的序列化替代方案也能很好地实现。谢谢! - diegoaguilar
1
@Diego:我已经擅自撤回了你的编辑,因为这样问题更有可能对未来的访问者有用。但是你的实现看起来很不错(至少从选择正确的 I/O 类的角度来看,我没有进行深入的审查)。 - Joachim Sauer
1
谢谢@Joachim,我接受并同意撤销编辑的观点。 - diegoaguilar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接