为啥 Windows 使用 UTF-16LE?

Posted

技术标签:

【中文标题】为啥 Windows 使用 UTF-16LE?【英文标题】:Why does Windows use UTF-16LE?为什么 Windows 使用 UTF-16LE? 【发布时间】:2021-05-10 07:36:45 【问题描述】:

大多数 Unix/POSIX/etc 世界使用 UTF-8 来表示文本,而 Windows 使用 UTF-16LE。

这是为什么呢?有很多人说 Windows API 是在 UTF-8(甚至我们所知的 Unicode)存在之前编写的(1、2、3),所以 UTF-16(甚至更早的 UCS- 2) 是他们拥有的最好的,将现有的 API 转换为 UTF-8 将是一项荒谬的工作。

但是这 2 项声明是否有任何官方来源? The official MSDN page for Unicode 让 UTF-16 看起来可能是可取的(尽管我自己不同意):

这些函数使用 UTF-16(宽字符)编码,这是 Unicode 最常见的编码,也是 Windows 操作系统上用于本机 Unicode 编码的一种。

是否有任何官方说明(或参与该项目的工程师)解释选择 UTF-16 的原因以及为什么 Windows 会/不会切换到 UTF-8强>?

【问题讨论】:

en.wikipedia.org/wiki/Unicode Linux UTF-8 和 Windows UTF-16 是怎样的?我所知道的任一系统上的大多数软件都允许您在多个选项中选择编码。 Unicode 的 16 位过去的遗迹散布在整个计算领域。查看 Java Character API,它是 char 类型。 IMO 一切都应该是 UTF-8,其余的都应该被弃用。 参考?检查两种编码的实施年份(UCS-2 与 UTF-8)。各种语言去了 UCS-2 (javascript)。 C为此实现了宽字符。并且很容易识别和区分旧/新。如果你在这里查看 SO,有很多人的编码不匹配(utf-8、latin-1、“ansi”)。从“全 16 位”(以前的 Unicode 原则)更改为多计划创建的“复杂”UTF-16。所以不是 UTF-8 更好,但使用 UCS-2……不知道什么是最好的 【参考方案1】:

“世界”很可能是指一切:操作系统(内部使用的编码)、可执行文件(支持的编码)、文件格式 (支持的编码)、文件系统(内部使用的编码)等等。

Windows 不会轻易切换,因为 PE 等基本文件格式(用于 EXE、DLL 等)有 resource strings 只能处理 WORDs 中的代码点.该格式已经是一个补丁上一个补丁,再添加一个扩展可能比仅仅使用二进制资源块并将它们转换为 UTF-8 更烦人。

自从在 Windows 中引入 Unicode 以来,它的 API 被布置为每个字符一个 WORD;每个函数的大多数 ANSI 版本只是调用该函数的 WIDE 版本的存根。对于 UTF-8,它不能被强制使用并且会破坏所有遗留代码 - 需要一个全新的 API(或每个函数的第三个版本)。只有少数函数是“未来就绪”的,因为您可以告诉它们文本的编码方式(显然是 MultiByteToWideChar())。

NTFS stores every character in WORDs 也是如此(因此间接支持 UTF-16),我看不出新版本会如何改变 - 我宁愿打赌一个全新的文件系统将介绍已淘汰的 NTFS,至少具有将所有文件名也存储在 UTF-8 中的新功能。

【讨论】:

"需要一个全新的 API(或每个函数的第三个版本)" - 并非如此,微软已经在 Windows 10 中实现了这一点,允许用户的默认代码页设置为 UTF-8,甚至只是通过清单以每个进程为基础。这允许现有的 Win32 A 函数现在可以使用 UTF-8 字符串,而不是(或至少除了)转换为 UTF-16 来调用 W 函数。 @RemyLebeau 但是有些函数没有A 对应项,例如ShutdownBlockReasonCreate 是的,但这是因为大多数此类功能是在微软将 Windows 的用户版(XP 及更早版本)和企业版(NT 及更高版本)合并到一个操作系统并迁移到全部之后引入的-Unicode,因此不再需要添加新的基于 ANSI 的 API。 A/W 函数用于从 Unicode 之前的时代继承下来的遗留 API。 是的,但我的意思是:如何在这些上使用 UTF-8?我的猜测:这是不可能的。除非他们得到 A 对应的。 您不能在较新的纯 UTF16 API 中使用 UTF-8,您必须根据需要在自己的代码中手动转换 UTF-8 UTF-16。【参考方案2】:

Windows 是最早采用 Unicode 的操作系统之一。那时,确实还没有 UTF-8,而 UCS-2 是 Unicode 最常用的编码。所以 Windows 最初的 Unicode 支持是基于 UCS-2。

当 Unicode 超过 UCS-2,UTF-8 和 UTF-16 变得更流行时,Windows 在不破坏大量现有代码的情况下切换到 UTF-8 为时已晚1,但是 UTF-16 向后兼容 UCS-2,因此 Microsoft 能够以最小的努力切换到 UTF-16,并且对现有用户代码几乎没有更改。

1:现在,20 多年后,在 Windows 10 中,Microsoft 才刚刚开始真正开始在 Win32 API 层支持 UTF-8,但该功能仍处于试验阶段,必须由用户手动启用或通过应用程序清单基于每个应用程序启用,并且通常需要更改用户代码以利用启用 UTF8 的 API 而不是基于 UTF16 的 API。

【讨论】:

谢谢!我觉得这是一个非常务实的解释。我希望微软*发布*/官方的理由来解释这个决定,所以我暂时不回答这个问题;不过,我对此表示赞同。 "在操作系统层支持 UTF-8" - 我怀疑这是否准确。据我所知,UTF-8 支持是作为 API 边界的翻译层实现的。操作系统内部仍然使用 UTF-16。如果你能证明我错了,让我感到惊讶。 @IInspectable 我改写了【参考方案3】:

Raymond Chen 实际上有一个“官方”答案——或者至少是来自 Microsoft 来源的答案(强调):

Windows 在大多数其他操作系统之前采用了 Unicode。[需要引用] 因此,Windows 对许多问题的解决方案不同于那些等待尘埃落定的解决方案。¹这方面最值得注意的例子是 Windows 使用 UCS-2 作为 Unicode 编码。 这是 Unicode Consortium 推荐的编码,因为 Unicode 1.0 仅支持 65536 个字符。² Unicode Consortium 五年后改变了主意,但到那时对于 Windows 来说已经太晚了,因为已经发布了 Win32s、Windows NT 3.1、Windows NT 3.5、Windows NT 3.51 和 Windows 95,它们都使用了 UCS-2

——The sad history of Unicode printf-style format specifiers in Visual C++

换句话说,Remy Lebeau 和 AmigoJack 都是对的——Windows 在 UTF-8 被推荐之前就采用了 Unicode(甚至存在?);当时,UCS-2 是标准,所以这就是 Windows 选择的。

当我们意识到整个人类语言需要超过 65,536 个字符(现在也需要表情符号?)时,Windows 已经发布了多个版本,这将是非常不切实际的(如果不是不可能的话)改变

感谢所有为这个问题提供答案的人!由于我一直在寻找官方来源,因此我将其标记为答案(尽管我将其标记为社区 wiki,因为它是一个合并)。

【讨论】:

以上是关于为啥 Windows 使用 UTF-16LE?的主要内容,如果未能解决你的问题,请参考以下文章

在UTF-16中,UTF-16BE,UTF-16LE,UTF-16的端点是计算机的字节序吗?

使用C ++将越南语字符编码为USASCII,ISO88591,UTF8,UTF16BE,UTF16LE,UTF16

在 Windows 和 Linux 下,在 C 中将 UTF-16 转换为 UTF-8

如何使用 C# 将 powershell 脚本编码为 base64 UTF16-LE 字符串

JAVA利用commons.net.ftp.FTPClient的storeFileStream方法TXT文件上传. 已经转码UTF-16LE,上传后内容乱码

java 读取必须使用特定字符集解码的文件(在本例中为UTF-16 LE)。