【问题标题】:Java stream misconceptions... some clarification?Java 流的误解......一些澄清?
【发布时间】:2011-10-24 22:09:07
【问题描述】:

我知道字节流处理字节,字符流处理字符...如果我使用字节流读取字符,这是否会限制我读取的字符种类?比如字节被读入8位字节,字符被读入16位字符……这是否意味着更多的字符可以用字符流而不是字节流来表示?

我最困惑的是字节流如何写入文件以供读取。如果我从网络套接字接收字节,我会将它们包装在InputStreamReader 中进行写入,这样我将获得字符流提供的字符转换逻辑。如果我使用FileInputStream 从文件中读取并使用FileOutputStream 写出,为什么当我使用文本编辑器打开该文件时它是可读的? FileOutputStream 如何处理字节?

【问题讨论】:

  • "字节流处理字节,字符流处理字符"。这里的官方术语是字节数据的 InputStream/OutputStream,字符的 Reader/Writer。

标签: java stream java-io


【解决方案1】:

这里的关键概念是character encoding:每个人类可读的字符都以某种方式编码成一个或多个字节。有很多字符编码。最受欢迎的是:

  • ASCII(7 位,剩余位未使用)将一个字符视为一个字节
  • UTF-8:最常见的字符表示为单个字节,不太常见的是 2 甚至更多

即使您在十六进制编辑器中打开文件,这些编码也是可读的。但是有很多字符编码没有这个特性,即UTF-16和UTF-32。

现在回到你的问题:InputStream 只给你一个字节流。如果您的字节代表用 ASCII 或 UTF-8 编码的字符,那么大多数情况下您都可以。但是如果这些字节代表更复杂的东西,比如 UTF-16,你绝对需要一个Reader。当然,读者必须知道底层InputStream 提供了哪种字符编码。这通常是初学者会遇到的问题 - Reader 未使用字符编码显式初始化通常会退回到系统默认值。

其他方式(与作家)类似。如果您只是将chars 转换为bytes,大多数情况下您会没事的。但是,如果您的字符包含不太流行的国家字母,您的输出将是格式错误/截断的。因此,您创建了一个Writer,它将每个给定的字符转换为一系列一个或多个字节。您有义务再次提供字符编码。

重要规则:

  • 总是在处理二进制数据(多媒体、ZIP 和 PDF 文件等)时使用InputStream
  • 总是在阅读文本(txt、HTML、XML...)时使用Reader
  • 总是在从字节流中读取字符时知道并指定字符编码,总是有意识地选择用于写入数据的字符编码。

【讨论】:

  • 很好的解释;那么,除了能够读取使用某些不规则字符集(如 UTF-16)编码的文本之外,字符流难道不应该有助于促进跨平台的字符集独立性吗?如果我定义要使用的字符编码,会发生这种情况?
  • 首先,UTF-16 不是不规则的。它被 Windows 和 Java 内部使用:-)。 Readers/Writers 正在帮助抽象底层字符编码。在 Java 中,您总是处理字符 (chars),并且您并不真正关心在 Reader/Writer 中使用哪种字符编码。例如,当一个库为您提供一个 Reader 实例供您读取时,您不必关心这个库使用什么编码,您会得到独立字符的编码。
【解决方案2】:

char 是一个 16 位字符串,表示 Unicode 字符。

byte 是一个 8 位字符串,表示 2 的补数。

这里重要的是它们都是位串。从技术上讲,一个char 就是2 个bytes。除了 Java 如何处理这两者的一些次要语义之外,仅此而已。就计算机(或Input/OutputStreams)而言,唯一的区别是它们持有的位数。

【讨论】:

  • 当然,但这并不能真正回答我的问题。显然 InputStream 只能读取用一个字节表示的字符。
  • 为什么?您可以让它读取 2 个字节并将其转换为 a char。它读取一个字节而不是其他任何内容的原因是因为它不需要。字节是 Java 直接支持的最小单位,任何其他数据类型都可以从它的组成字节中重构。
  • 好酷;但是,开箱即用,字符流将以字节为单位读取,在 1 或 2 中表示某个编码字符?
  • 它将读取2个字节,然后使用指定的字符集将其转换为对应的Unicode字符。
【解决方案3】:

我认为你需要掌握一个字节和一个字符之间的关系才能得到你的澄清。

恕我直言,这个问题的公认答案非常明确:Why does a byte in Java I/O can represent a character?

我也想看看byte stream and character stream

如果你不想让乔尔抓住你,让你在潜水艇里剥洋葱 6 个月,请阅读http://www.joelonsoftware.com/articles/Unicode.html

【讨论】:

  • 阅读乔尔的解释对我帮助很大;每个人都应该阅读它。
【解决方案4】:

java中所有的IO流都只是底层的字节流。字节到字符(反之亦然)的转换是使用编码完成的。但在这一切之下,它们都是字节。

【讨论】:

    【解决方案5】:

    回答您的问题:

    我了解字节流处理字节和字符流 处理字符...如果我使用字节流读取字符, 这会限制我阅读的字符类型吗?

    字符不是字节。根据选择的编码方案,一个字符存储在一个或多个字节中。编码方案消除/扩展了您可以阅读的字符种类的限制。

    例如,字节被读取为 8 位字节,字符被读取 作为 16 位字符...这是否意味着可以有更多字符 用字符流而不是字节流来表示?

    在某种程度上,是的。

    我最困惑的是字节流如何写入 文件供阅读。如果我从网络套接字接收字节,我 会将它们包装在 InputStreamReader 中进行写入,这样我会 获取字符流提供的字符转换逻辑。 如果我使用 FileInputStream 从文件中读取并使用 FileOutputStream,为什么当我用文本打开这个文件时它是可读的 编辑? FileOutputStream 如何处理字节?

    对于与字符对应的字节/数据,您应该使用OutputStreamWriter 写入文件并使其可以使用文本编辑器读取。您可以在创建时指定编码,流将对您的文本数据执行编码。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-11-08
      • 2014-07-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-29
      • 1970-01-01
      • 2014-03-29
      相关资源
      最近更新 更多