我该怎么用? UTF8还是UTF16?

时间:2012-03-22 08:22:28

标签: delphi utf-8 utf-16

我必须在国际上发布我的应用。

假设我有一个控件(如备忘录),用户输入一些文字。用户可以是日语,俄语,加拿大等。 我想将字符串保存为磁盘作为TXT文件供以后使用。我将使用MY OWN函数来编写文本而不是TMemo.SaveToFile()。

如何将字符串保存到磁盘?采用UTF8或UTF16格式?

3 个答案:

答案 0 :(得分:30)

它们之间的主要区别在于UTF8向后兼容ASCII。只要您只使用前128个字符,非Unicode识别的应用程序仍然可以处理数据(这可能是优势或劣势,具体取决于您的方案)。特别是,当切换到UTF16 时,每个 API函数需要针对16位字符串进行调整,而使用UTF8时,如果不执行任何字符串处理,通常可以保持旧的API函数不受影响。 UTF8也不依赖于字节序,而UTF16则不依赖于字符串I / O.

一个常见的误解是UTF16更容易处理,因为每个字符总是占用两个字节。不幸的是,这不是真的。 UTF16是一种可变长度编码,其中一个字符可能占用2或4个字节。因此,与UTF8相关的关于可变长度问题的任何困难也适用于UTF16。

最后,存储大小:关于UTF16的另一个常见误区是,对于大多数外语来说,它比UTF8更具存储效率。 UTF8为所有欧洲语言提供 less 存储,每个字符可以编码一个或两个字节。非BMP字符在UTF8和UTF16中占用4个字节。 UTF16占用较少存储空间的唯一情况是文本主要由U + 0800到U + FFFF范围内的字符组成,其中存储了中文,日文和印地文的字符。

James McNellis在BoostCon 2014上发表了精彩演讲,详细讨论了不同编码之间的各种权衡。即使谈话的标题是 Unicode in C ++ ,整个上半部分实际上与语言无关。一个video recording of the full talk is available at Boostcon's Youtube channel,而slides can be found on github

答案 1 :(得分:27)

取决于您的数据的语言。

如果您的数据主要使用西方语言并且您希望减少所需的存储量,请使用UTF-8,因为这些语言大约需要UTF-16的一半存储空间。您将在读取数据时支付罚金,因为它将/需要转换为UTF-16,这是Windows默认值并由Delphi(Unicode)字符串使用。

如果您的数据主要是非西方语言,UTF-8可以占用比UTF-16更多的存储空间,因为每个字符可能需要 6 4 字节对于一些。 (见@KennyTM的评论)

基本上:使用用户数据的代表性样本进行一些测试,并查看哪些在存储要求和加载时间方面表现更好。我们有一些惊喜,UTF-16比我们想象的要慢。由于磁盘访问,因为UTF-16中的数据量更大,因此无需从UTF-8转换为UTF-16的性能提升已丢失。

答案 2 :(得分:10)

首先,请注意Windows下的标准编码是UCS2(直到Windows 2000)或UTF-16(自XP以来),Delphi本机“string”类型使用相同的本机格式,因为Delphi 2009年(string=UnicodeString char=WideChar)。

在所有情况下,假设1 WideChar == 1个Unicode字符是不安全的 - 这是surrogate问题。

关于UTF-8或UTF-16选择,它取决于存储本身:

  • 如果您的文件是纯文本文件(包括XML),您可以使用UTF-8或UTF-16 - 但您必须在文件开头use a BOM ,否则应用程序(如记事本)可能会在打开时混淆 - 对于XML,这由您的库处理(如果不是,则更改为另一个库);
  • 如果您确定您的内容大多是7位ASCII,请使用UTF-8和相关的BOM;
  • 如果您的文件是某种数据库或自定义二进制格式,当然最好的格式是UTF-16 / UCS2,即默认的Delphi 2009+ {{ 1}}布局,当然还有默认的数据库API布局;
  • 某些文件格式需要或更喜欢UTF-8(如JSON甚至 SQLite3 ),即使UTF-8文件对于亚洲字符大于UTF-16也是如此。

例如,我们在客户端 - 服务器框架中使用了UTF-8,因为我们使用JSON作为交换格式(需要UTF-8),并且因为 SQlite3 喜欢UTF-8。当然,我们必须编写一些专用的函数和类,以避免转换为string(自{Delphi 2009以来string类型的转换速度很慢,并且在与{{{{}}一起使用时可能会丢失一些数据1}}在Delphi 2009之前输入。请参阅this postthis unit)。最简单的方法是依赖string=UnicodeString类型,使用直接处理UTF-16编码的RTL函数,并避免转换。不要忘记your previous question

如果磁盘空间和读/写速度有问题,请考虑使用压缩而不是更改编码。有实时压缩(比ZIP快),如LZO或我们的SynLZ。