在 java 中使用 UTF-8 字符集输出流将 UTF-16 字符写入文件,但文件中的结果数据仍为 UTF-16。为什么?

Written UTF-16 character to a file by using UTF-8 charset output stream in java but resulting data on file is still UTF-16. why?

创建了一个简单的 java 程序来查看 utf 8 字符集是否可以保存 utf16 字符,它确实能够保存它。为什么? 如果 UTF-08 可以保存 UTF-16 字符,那么使用 UTF-16 和 UTF-8 有什么区别。

两个测试字符的 unicode 值都超出了 UTF-8 范围,即 256。

✈ unicode 值:9992
❄ unicode 值:10052

请看示例程序:-

import java.io.*;
import java.nio.charset.Charset;

public class UTFSizeTest {

    public static void main(String[] args) throws IOException {
        System.out.println("Default Charset=" + Charset.defaultCharset());
        write("UTF-16");
        write("UTF-8");
        write(null);
    }

    private static void write(String utf) throws IOException {
        final String fileName = "someFile" + utf;

        Writer writer;

        if (utf == null) {
            writer = new OutputStreamWriter(new FileOutputStream(fileName));
        } else {
            writer = new OutputStreamWriter(new FileOutputStream(fileName), utf);
        }


        for (int i = 0; i < 2; i++) {
            writer.write("✈ ❄");
            writer.write("\n");
        }

        writer.close();

        System.out.println(fileName + " size: "+ new File(fileName).length());
    }
}

使用 utf-16 和 utf-8 在两个文件上写入相同的数据:-
✈ ❄
✈ ❄

从控制台输出中可以看出,UTF-16 和 UTF-8 的文件大小也几乎相同。
控制台输出如下:-
默认字符集=UTF-8
someFileUTF-16 大小:18
someFileUTF-8 大小:16
someFilenull 大小:16

如果 utf-08 可以保存 16 位 unicode 就好了,为什么要在 java.

中使用 uff-16

谢谢。

我问这个问题是因为我的无知。 我虽然 UTF-8 最多只能保存字符点 8 位,而 Unicode 需要 UTF-16 或 Unicode 字符表示由 2 个字节或 16 位表示的字符。

但是看了一些论坛后我发现UTF-8、UTF-16和UTF-32都是Unicode字符的不同编码方式,实际上UTF-8最多可以表示6个字符bytes/48位。

谢谢

Created a simple java program to see if utf 8 charset can save utf16 character

可以。 UTF-8 和 UTF-16 只是同一个 Unicode 字符集的不同编码。两种编码都旨在支持所有 Unicode 代码点,包括现在和可预见的未来。

and it does able to save it. Why?

因为它们都支持相同的 Unicode 代码点。按照设计,在各种 UTF 之间进行转换是一种无损操作。

If UTF-08 can save UTF-16 characters than whats the difference in using UTF-16 and UTF-8.

UTF-8 优于 UTF-16 的主要原因是:

  1. UTF-8 向后兼容 7 位 ASCII,因此很多遗留代码可以在不中断的情况下迁移到 UTF-8。

  2. 对于大多数语言,尤其是基于拉丁语的语言,UTF-8 比 UTF-16 更紧凑,因此可以节省内存、磁盘 space 和带宽。但是,在某些情况下,主要是亚洲语言,但也有符号(如您的示例),其中 UTF-16 实际上比 UTF-8 更紧凑。

please see the sample program:-
...
Data written same on both files using utf-16 and utf-8 :-

是的,它们代表相同的 Unicode 代码点,因此它们呈现相同的 Unicode 文本 viewer/editor.但是它们的物理字节有很大的不同:

✈
UTF-8:    e2 9c 88
UTF-16LE: 08 27
UTF-16BE: 27 08

❄
UTF-8:    e2 9d 84
UTF-16LE: 44 27
UTF-16BE: 27 44

Size of the files is also almost the same for UTF-16 and UTF-8 as can seen on console output.

在上面的示例中,您选择了 2 个不需要 UTF-16 代理项对对其进行编码的 Unicode 代码点,因此它们在 UTF-16 中使用 2 个字节而不是 4 个字节。在 UTF-8 中,每个占用 3 个字节,但大小差异通过它们之间的 1 字节 U+0020 SPACE 字符减少。尝试使用更多的低代码点值和高代码点值组合来编写更长的字符串,您应该会看到文件大小的变化范围更大。

If utf-08 can save 16 bits unicode just fine fine than why to use uff-16 in java.

尽管 UTF-8 和 UTF-16 都是可变长度编码,但 UTF-16 的可变长度往往小于 UTF-8。 UTF-8 的 1、2 和 3 字节格式中的所有代码点都适合 UTF-16 的 2 字节格式,使 UTF-16 比 UTF-8 更接近固定长度。这也意味着 UTF-16 更容易在内部向前和(特别是)向后寻找,每个代码点只需跳转 2 或 4 个字节,而使用 UTF-8 则每个代码点必须跳转 1、2、3 或 4 个字节代码点,因此 UTF-8 的解码逻辑比 UTF-16 更复杂。

请记住,当 Java、Windows 等采用 Unicode 时,那是在 UTF-16 存在之前,当时所有可用的代码点很容易适合 UCS-2,即固定长度的编码。直到后来,Unicode 才超越了 UCS-2,才发明了 UTF-16 来取而代之。到那时,重新编写已迁移到 Unicode 的代码为时已晚,因此 UTF-16 必须保持与 UCS-2 的向后兼容性。此外,现实世界中使用的许多 Unicode 数据仍然倾向于适合 UCS-2,只有更高的代码点才真正需要额外的字节来编码 UTF-16 代理项。

因此,这通常使 UTF-16 成为处理数据的更合适选择。与 UTF-8 相比,它是内存使用和处理开销之间更好的折衷,至少在处理非 ASCII 字符时是这样。但 UTF-8 向后兼容 ASCII,它往往是一种更适合存储和交换数据的格式。