ChatGPT解决这个技术问题 Extra ChatGPT

为什么 .net 对字符串使用 UTF16 编码,但默认使用 UTF-8 来保存文件?

From here

本质上,字符串使用 UTF-16 字符编码形式

但是当保存 vs StreamWriter 时:

此构造函数使用 UTF-8 编码创建一个没有字节顺序标记 (BOM) 的 StreamWriter,

我看过这个示例(已删除断开的链接):

https://i.stack.imgur.com/QYDgv.jpg

看起来 utf8 对于某些字符串较小,而 utf-16 在某些其他字符串中较小。

那么为什么 .net 使用 utf16 作为字符串的默认编码,使用 utf8 作为保存文件的默认编码呢?

谢谢你。

ps 我已经读过the famous article

来自 Eric Lippert 的 This post 详细说明了做出该决定的原因。
@Lukazoid 很棒的帖子,但请注意评论,Hans Passant 不同意令人信服的论点。
简短的回答是 UTF16 是不可移植的,而 UTF8 是超级便携的。

J
Jon Skeet

如果您乐于忽略代理对(或等效地,您的应用程序需要基本多语言平面之外的字符的可能性),UTF-16 有一些很好的属性,基本上是因为每个代码单元总是需要两个字节并代表所有 BMP 字符每个单个代码单元。

考虑原始类型 char。如果我们使用 UTF-8 作为内存中的表示并想要处理 all Unicode 字符,那应该有多大?它可能最多 4 个字节......这意味着我们总是必须分配 4 个字节。那时我们不妨使用 UTF-32!

当然,我们可以使用 UTF-32 作为 char 表示,但在 string 表示中使用 UTF-8,我们可以随时转换。

UTF-16 的两个缺点是:

每个 Unicode 字符的代码单元数是可变的,因为并非所有字符都在 BMP 中。在表情符号流行之前,这并没有影响许多日常使用的应用程序。如今,对于消息传递应用程序等,使用 UTF-16 的开发人员确实需要了解代理对。

对于纯 ASCII(至少在西方有很多文本),它占用的空间是等效 UTF-8 编码文本的两倍。

(作为旁注,我相信 Windows 使用 UTF-16 处理 Unicode 数据,出于互操作的原因,.NET 效仿是有意义的。不过,这只是将问题推向了一步。)

考虑到代理对的问题,我怀疑如果一种语言/平台是从头开始设计的,没有互操作要求(但基于 Unicode 的文本处理),UTF-16 不会是最佳选择。 UTF-8(如果您想要内存效率并且不介意在获取第 n 个字符方面的一些处理复杂性)或 UTF-32(反之亦然)将是更好的选择。 (由于不同的规范化形式,即使到达第 n 个字符也有“问题”。文本很难......)


UTF-8 的重点在于,如果您需要每个字符 6 个字节来真正表示所有可能性,那么任何小于 UTF-32 的内容都是需要特殊情况和额外代码的问题。所以 UTF-16 和 UTF-8 都是不完美的。但是,由于 UTF-8 是大小的一半,您不妨使用它。在它上面使用 UTF-16 将一无所获(增加的文件/字符串大小除外)。当然,有些人会使用 UTF-16 并无知地认为它可以处理所有字符。
我已经读了 14 遍了。我仍然不明白这一行:每个代码单元的大小是恒定的。 AFAIK 大小可以是 2,3,4 字节(在 utf-16 中),那么这里的常量是什么?
@gbjbaanb:不,.NET 使用 UTF-16。因此,当需要 BMP 之外的任何内容时,将使用代理对。每个字符都是一个 UTF-16 代码单元。 (据我所知,也没有 UCS-16 这样的东西——我认为你的意思是 UCS-2。)
@RoyiNamir:不,UTF-16 代码单元的大小始终为 2 个字节。 Unicode 字符采用一个代码单元(对于基本多语言平面)或两个代码单元(对于字符 U+10000 及以上)。
@FernandoPelliccioni:您如何精确定义“可变宽度编码”?刚刚重读定义,我同意我对“代码单元”的确切含义感到困惑,但 UTF-8 和 UTF-16 都是可变宽度,因为“它们可以采用可变数量的字节来表示单个 Unicode 代码点”。对于 UTF-8,它是 1-4 个字节,对于 UTF-16,它是 2 或 4。现在将检查我的其余答案是否精确。
H
Hans Passant

与许多“为什么选择这个”问题一样,这是由历史决定的。 Windows 于 1993 年成为其核心的 Unicode 操作系统。当时,Unicode 仍然只有 65535 个代码点的代码空间,现在称为 UCS。直到 1996 年,Unicode 才获得了补充平面,将编码空间扩展到一百万个代码点。并使用代理对将它们放入 16 位编码中,从而设置 utf-16 标准。

.NET 字符串是 utf-16,因为它非常适合操作系统编码,不需要转换。

utf-8 的历史更加模糊。绝对超越 Windows NT,RFC-3629 始于 1993 年 11 月。它需要一段时间才能站稳脚跟,互联网发挥了重要作用。


R
Remy Lebeau

UTF-8 是文本存储和传输的默认设置,因为它对于大多数语言来说是一种相对紧凑的形式(有些语言在 UTF-16 中比在 UTF-8 中更紧凑)。每种特定语言都有更有效的编码。

UTF-16 用于内存中的字符串,因为它可以更快地解析每个字符并直接映射到 unicode 字符类和其他表。 Windows 中的所有字符串函数都使用 UTF-16 并且已经使用了多年。