Java:用于Sytem.out / in / err文件的隐式编码是什么?

问题描述

一个任务:我想从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则没有。 他们怎么知道文件的编码?

感谢您的澄清。

解决方法

我想通过
从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中设置的语言环境(或Windows代码页)相匹配。操作系统(如上所述)用于Java默认值,因此您可以使用默认值。如果输入将从文件重定向(或在Unix上为“ heredoc”,实际上是一个临时文件),则取决于文件中的内容。如果输入将从另一个程序的管道中重定向(在某些Unix shell中,包括进程替换),则取决于其他程序输出的内容-如果它在同一系统中运行,则 ( (但不确定)要使用与Java进程相同的语言环境。

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

(此外:“根据”在这里不是语法。您可以说“ [[/]]对应问题”,而“ [[]]同一问题”是正确的并且更加清楚。)

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

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

还有什么字符集??

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

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

这些是不同的。它们不能以字节为单位,至少没有明显的作用。

首先考虑String,Java String被定义为由16位char组成,而不是字节。最初,当Unicode也是16位时,它们才是真正的字符(现在称为UCS-2)。当Unicode增长到16位以上,但Java不能轻易更改以遵循时,这些变成了UTF-16代码元素,它们大多是 个字符,但在 pairs中使用一组称为代理的字符代表“补充”字符。当且仅当所有UTF-16代码元素都容纳在一个字节中时,Java的最新版本(9版,IIRC)实际上将存储 String数据作为单个字节存储,这等效于在ISO-8859-1(Latin-1)字符集中。但这纯粹是内部的。 API仍会接受并返回char char[]等。因此,不会完成NIO /字符集模型所设想的类型的编码和解码,并且不会涉及任何字符集。

尽管也存在面向字节的Piped{Input,Output}Stream,但Piped{Reader,Writer}并未使用它们;它们只是存储写侧提供的char序列,然后在读侧返回它们。再次,不进行编码或解码,并且不涉及任何字符集。

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

(edit)从Java 11开始不再适用;现在,他们具有带字符集的ctor,并且未指定字符集的ctor被记录为使用默认字符集;请参阅FileReaderFileWriter。需要明确的是,阅读器不知道文件内容的实际编码(假设有一些编码),它只知道您说的是什么或默认值;如果与实际文件内容不匹配,则可能会获得部分或全部垃圾数据。 Writer会编写您指定或默认的编码,因此内容(或附加时至少为 new 内容)将采用该编码。 在{11之前的class summaries说:“此类的构造函数假定默认字符编码和默认字节缓冲区大小是适当的。”