我想从 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 .err 是PrintStream(或子类)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,并且那些没有指定字符集的被记录为使用默认字符集;见FileReader 和FileWriter。需要明确的是,Reader 不知道文件内容的实际编码(假设有一些),它只知道您说要使用的内容或默认值;如果这与实际文件内容不匹配,您可能会获得部分或全部垃圾数据。 Writer 会写入您指定或默认的编码,因此内容(或附加时至少 new 内容)将采用该编码。
在 11 之前,classsummaries 表示“此类的构造函数假定默认字符编码和默认字节缓冲区大小是合适的。”