第一个任务:我想从 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 的构造函数不同, 具有带有字符集的构造函数,文件读取器/编写器没有。 他们怎么知道文件的编码???
感谢您的澄清。
我想从 System.in 读到读者...via
InputStreamReader cin = new InputStreamReader(System.in);
目前尚不清楚默认编码是什么。据我了解,System.in 只是一个字节流。而 InputStreamReader 读取字符。但是 InputStream 的构造函数在哪里知道字符集呢?
一个可能假设想要了解Java标准库元素的人可以想象地查看文档,即该ctor的Javadoc,它说
创建使用默认字符集的输入流读取器。
在旧版本中,这实际上是一个超链接,但不再是。但是,页面顶部描述整个类的文本说
InputStreamReader 是从字节流到字符流的桥梁:它读取字节并使用指定的字符集将它们解码为字符。它使用的字符集可以按名称指定,也可以显式给出,或者可以接受平台的默认字符集。
并且该字符集确实超链接到类java.nio.charset.Charset
,该类说
Java 虚拟机的每个实例都有一个缺省字符集,该字符集可能是标准字符集之一,也可能不是标准字符集之一。默认字符集在虚拟机启动期间确定,通常取决于基础操作系统使用的区域设置和字符集。
并记录了一个可以调用以找出该默认值的方法。
我必须应用特定的字符集吗?如果是,是哪一个还是我必须把它留掉?
取决于您将要读取的数据。如果Java使用来自"终端"(在Unix中)或"控制台"(在Windows中)的标准输入运行,则通常用户输入将与操作系统中设置的区域设置(或Windows代码页)匹配,如上所述用于Java默认值,因此您可以使用默认值。如果输入将从文件(或在Unix上重定向"heredoc",这实际上是一个临时文件),则取决于文件中的内容;如果输入将从另一个程序的管道重定向(在某些Unix shell上,包括进程替换),这取决于其他程序输出的内容 - 如果它在同一系统中运行,则可能(但不确定)使用与Java进程设置的相同语言环境。
根据有关System.out和System.err的问题。两者都似乎是打印流,特别是读取字节。
(旁白:"根据"在那里不是语法。你可以说"[the/a]相应的问题",但只有"[the]相同的问题"是正确的,而且更清楚。
是的,这里System.out .err
PrintStream
(或子类)Javadoc的实例,这是一种特例和混合体;它处理写入(不读取)字节的方式与任何其他OutputStream
相同,但也具有与PrintWriter
相同的print*
和printf/format
方法。实际的PrintWriter
会将输出格式化(如有必要)为字符,并(通常)将它们传递给OutputStreamWriter
,该将字符编码为字节并传递到底层流,但PrintStream
同时进行格式化和编码本身,直接输出字节。查看 ctor 列表,您可以看到您可以指定字符集名称或对象,也可以使用默认值;System.out .err
的实现使用默认值。
如果您确实在这些PrintStream
(流部分)上创建了自己的OutputStreamWriter
,则可以指定任何字符集或使用默认值 - 尽管如果您要使用默认值,为什么不直接使用PrintStream
?
还有字符集是什么????
如果你的意思是这个概念,请参阅我上面链接的类文档。如果您的意思是给定 JVM 上可用的特定字符集,则可能会有所不同。可以使用该类中的静态方法availableCharsets()
某个时间点获取当前列表。
我对PipedReader/Writer也有同样的问题。至少它们必须重合,对吧?
For StringWriter/Reader:与字符串相同的编码,即utf8,对吧?
这些是不同的。它们不以字节为单位工作,至少不可见。
首先String
,JavaString
被定义为由 16 位char
组成,而不是字节。最初,当Unicode也是16位时,这些是真正的字符(现在称为UCS-2)。当Unicode超过16位,但Java不能轻易改变时,这些成为UTF-16代码元素,这些元素主要是字符,但一组称为代理项,成对使用来表示"补充"字符。最新版本的Java(9 up,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开始不再如此;现在他们确实有带有字符集的ctor,并且那些没有指定字符集的被记录为使用默认字符集;参见FileReader和FileWriter。需要明确的是,阅读器不知道文件内容的实际编码(假设有一些),它只知道你说要使用什么或默认值;如果这与实际文件内容不匹配,您可能会得到部分或全部乱码数据。编写器确实会写入您指定或默认的编码,因此内容(或至少追加时的新内容)将采用该编码。 在 11 之前,类摘要说"此类的构造函数假定默认字符编码和默认字节缓冲区大小是合适的。