为什么说:CharacterStream类是用来执行16位Unicode字符的input/output?

Why is it said: CharacterStream classes are used to perform the input/output for the 16-bit Unicode characters?

When an I/O stream manages 8-bit bytes of raw binary data, it is called a byte stream. And, when the I/O stream manages 16-bit Unicode characters, it is called a character stream.

Byte stream清楚了。它使用 8 位字节。所以如果我要写一个 character 使用 3 bytes 它只会写它的最后 8 bits !从而使输出不正确。

所以这就是我们使用 character streams 的原因。假设我想写拉丁文大写字母 。我需要 3 个字节 来以 UTF-8 格式存储。但是说我也想存储'normal'A。现在需要 1 个字节 来存储。

你看到规律了吗?在我们转换它们之前,我们无法知道写入任何这些 字符 需要多少字节。所以我的问题是为什么说character streams manage 16-bit Unicode characters?如果我写的 需要 3 个字节 ,它不会像 [=18] 那样将其削减到 最后 16 位 =] 剪切最后 8 位 。那句话到底是什么意思?

在Java中,一个String是由一个16位的char序列组成的,表示以UTF-16编码存储的文本。

A Charset 是描述如何将 Unicode 字符转换为字节序列的对象。 UTF-8 是字符集的一个例子。

一个像Writer这样的字符流,当它输出到一个包含字节的东西——一个文件,或者一个像OutputStream这样的字节输出流——使用一个Charset来将 Strings 转换为简单的字节序列以进行输出。 (从技术上讲,它将 UTF-16 字符转换为 Unicode 字符,然后使用 Charset 将它们转换为字节序列。)从字节源读取时,Reader 执行反向转换。

在UTF-16中,Ạ表示为16位char0x1EA1。它在 UTF-16 中只需要 16 位,而不是像在 UTF-8 中那样需要 24 位。

如果您将它转换为使用 UTF-8 编码的字节,如下所示:

ByteArrayOutputStream baos = new ByteArrayOutputStream();
Writer writer = new OutputStreamWriter(baos, StandardCharsets.UTF_8);
writer.write("Ạ");
writer.close();
return baos.toByteArray();

然后你会得到预期的 3 字节序列 0xE1 0xBA 0xA1。

在Java中,一个字符(char)总是16位,从它的最大值可以看出——65535。这就是引号没有错的原因。 16位确实是一个字符

“如何将所有 Unicode 字符存储在 16 位中?”你可能会问。这是在 Java 中使用 UTF-16 编码完成的。这是它的工作原理(用非常简单的术语):

基本多语言平面中的每个 Unicode 代码点都以 16 位编码。 (是的,16 位就足够了)BMP 之外的每个代码点都用一对 16 位字符编码,称为代理对。

"Ạ" (U+1EA0) 在BMP中,所以可以用16位编码。

你说:

Say I want to write Latin Capital Letter Ạ. I would need 3 bytes for storing in UTF-8. But say I also want to store 'normal' A. Now it would take 1 byte to store!

这并没有使引用不正确。该流仍然“管理 16 位字符”,因为这是您将使用 Java 代码赋予它的内容。当你在 PrintStream 上调用 println 时,你给它一个 String,它是引擎盖下的一堆 char,这是一堆 16 位.所以它实际上是在管理一个 16 位字符流。只是它以不同的编码输出它们。

可能值得一提的是当您尝试打印不在 BMP 中的字符时会发生什么。这仍然不会使报价不正确。报价没有说“代码点”。它说“字符”,它指的是您正在打印的代理对的 upper/lower 代理。