【问题标题】:Java: Which are the implicit encodings used for Sytem.out/in/err, files?Java:Sytem.out/in/err 文件使用了哪些隐式编码?
【发布时间】:2020-11-11 00:12:00
【问题描述】:

第一个任务:我想从 System.in 读入阅读器。 看来这是通过

InputStreamReader cin = new InputStreamReader(System.in);

还有其他构造函数,包括编码。 目前尚不清楚默认编码是什么。 据我了解, System.in 只是一个字节流。 而 InputStreamReader 读取字符。 但是 InputStream 的构造函数在哪里知道字符集? 我必须应用特定的字符集吗?如果是这样,或者我必须把它留下吗?

根据有关 System.out 和 System.err 的问题。 两者似乎都是打印流,尤其是读取字节。

OutputStreamWriter out  = new OutputStreamWriter(System.out);

确定选择正确的编码还是我必须使用不同的构造函数?

System.err 呢?

还有什么字符集????

我对 PipedReader/Writer 有同样的问题。 至少它们必须重合,对吧?

对于StringWriter/Reader:与字符串相同的编码,即utf8,对吗?

关于文件的最后一个问题。 FileReader/Writer 是 InputStreamReader/Writer 的子类。 这似乎是合理的,因为文件是一个字节序列。 但与 InputStreamReader/Writer 的构造函数不同, 有带字符集的构造函数,FileReader/Writer 没有。 他们怎么知道文件的编码???

感谢您的澄清。

【问题讨论】:

    标签: java encoding charset


    【解决方案1】:

    我想从 System.in 读入阅读器...通过
    InputStreamReader cin = new InputStreamReader(System.in);
    目前尚不清楚默认编码是什么。据我了解, System.in 只是一个字节流。而 InputStreamReader 读取字符。但是 InputStream 的构造函数在哪里知道字符集呢?

    一个可能想了解 Java 标准库元素的人可能会查看文档,即the Javadoc for that ctor,上面写着

    创建一个使用默认字符集的 InputStreamReader。

    在旧版本中,这实际上是一个超链接,但不再是。然而,页面顶部的文字描述了整个类

    InputStreamReader 是从字节流到字符流的桥梁:它读取字节并使用指定的字符集将它们解码为字符。它使用的字符集可以由名称指定,也可以显式给出,或者可以接受平台的默认字符集。

    那个字符集确实超链接到the class java.nio.charset.Charset,上面写着

    Java 虚拟机的每个实例都有一个默认字符集,它可能是也可能不是标准字符集之一。默认字符集在虚拟机启动期间确定,通常取决于底层操作系统使用的语言环境和字符集。

    并记录 method you can call 以找出默认值。

    我必须应用特定的字符集吗?如果是这样,或者我必须把它留下吗?

    取决于您将要读取的数据。如果 Java 使用来自“终端”(在 Unix 中)或“控制台”(在 Windows 中)的标准输入运行,用户输入的通常将匹配在操作系统,如上用于Java默认,所以你可以使用默认。如果输入将从文件(或 Unix 上的“heredoc”,实际上是一个临时文件)重定向,则取决于文件中的内容;如果输入将从另一个程序的管道重定向(在某些 Unix shell 上,包括进程替换),这取决于其他程序输出的内容——如果它在同一系统中运行,它是可能(但不确定)使用与为 Java 进程设置的语言环境相同的语言环境。

    根据有关 System.out 和 System.err 的问题。两者似乎都是打印流,尤其是读取字节。

    (除此之外:'according' 在那里不符合语法。你可以说'[the/a]相应的问题',但只是'[the] same question'是正确且更清晰的。)

    是的,System.out .errPrintStream(或子类)Javadoc here 的实例,这是一种特殊情况和一种混合;它处理写入(不读取)字节的方式与任何其他OutputStream 相同,但也具有与PrintWriter 相同的print*printf/format 方法。实际的PrintWriter 将(如果需要)将输出格式化为字符,并(通常)将它们传递给OutputStreamWriter,后者将字符编码为字节并传递给底层流,但PrintStream 本身进行格式化和编码,直接输出字节。查看 ctor 列表,您可以看到您可以指定字符集名称或对象,也可以使用默认值; System.out .err 的实现使用默认值。

    如果您确实在这些PrintStreams 的(流部分)上创建了自己的OutputStreamWriter,您可以指定任何字符集或使用默认值——尽管如果您要使用默认值,为什么不直接直接使用PrintStream

    还有什么字符集????

    如果您指的是概念,请参阅我上面链接的类文档。如果您的意思是给定 JVM 上可用的特定字符集,那可能会有所不同。您可以使用该类中的静态方法availableCharsets() 获取某个时间点的当前列表。

    我对 PipedReader/Writer 有同样的问题。至少它们必须重合,对吧?
    对于StringWriter/Reader:和字符串一样的编码,即utf8,对吧?

    这些是不同的。它们不能以字节为单位工作,至少不可见。

    首先以String 为例,Java String 被定义为由 16 位 chars 组成,而不是字节。最初,当 Unicode 也是 16 位时,这些是真正的字符(现在称为 UCS-2)。当 Unicode 超过 16 位但 Java 无法轻易更改时,这些代码元素变成了 UTF-16 代码元素,它们大部分是字符,但有一组,称为代理,用于对 表示“补充”字符。 Java 的最新版本(9 以上,IIRC)实际上将String 数据存储为单个字节当且仅当所有 UTF-16 代码元素都适合一个字节,这相当于它们在ISO-8859-1 (Latin-1) 字符集。但这纯粹是内部的; API 仍然接受并返回char char[] 等。因此没有完成 NIO/Charset 模型所设想的类型的编码和解码,并且不涉及任何字符集。

    虽然面向字节的Piped{Input,Output}Stream也存在,但Piped{Reader,Writer}不要使用它们;相反,它们只是存储在写入端提供的char 序列,然后在读取端返回它们。同样没有进行编码或解码,也没有涉及任何字符集。

    关于文件的最后一个问题。 FileReader/Writer 是 InputStreamReader/Writer 的子类。这似乎是合理的,因为文件是一个字节序列。但与 InputStreamReader/Writer 的构造函数不同,后者具有带字符集的构造函数,FileReader/Writer 没有。他们怎么知道文件的编码???

    (编辑)从 Java 11 开始,这不再适用;现在他们确实有带有字符集的ctors,并且那些没有指定字符集的被记录为使用默认字符集;见FileReaderFileWriter。需要明确的是,Reader 不知道文件内容的实际编码(假设有一些),它只知道您说要使用的内容或默认值;如果这与实际文件内容不匹配,您可能会获得部分或全部垃圾数据。 Writer 会写入您指定或默认的编码,因此内容(或附加时至少 new 内容)将采用该编码。 在 11 之前,classsummaries 表示“此类的构造函数假定默认字符编码和默认字节缓冲区大小是合适的。”

    【讨论】:

    • 我确实阅读了 api 文档。我什至找到了 Charset.defaultCharset() 方法,但不确定这是否是 InputStreamReader 文档中的意思。我什至阅读了资料,但很快就进入了私人课程。
    • 啊,关于 FileReader/Writer,带有 Charset 的构造函数似乎是在 java 8 和 java 11 之间添加的。
    • 你是对的:它们是在 11 中添加的,这在每个单独的 ctor doc 条目中都有指示,但在摘要中没有。固定。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多