UTF-8和 UTF-16的区别?

UTF-8和 UTF-16的区别? 我们为什么需要这些?

MessageDigest md = MessageDigest.getInstance("SHA-256");
String text = "This is some text";


md.update(text.getBytes("UTF-8")); // Change this to "UTF-16" if needed
byte[] digest = md.digest();
133249 次浏览

它们只是表示 Unicode 字符的不同方案。

两者都是可变长度-UTF-16在包含大多数常用字符的基本多语言平面(BMP)中对所有字符使用2字节。

UTF-8对 BMP 中的字符使用1到3个字节,对于当前 Unicode 范围 U + 0000到 U + 1 FFFFFFF 中的字符使用最多4个字节,如果有必要的话,可以扩展到 U + 7 FFFFFFF... ... 但值得注意的是,所有 ASCII 字符都用一个字节来表示。

对于消息摘要来说,选择哪个并不重要,只要尝试重新创建摘要的每个人都使用相同的选项。

有关 UTF-8和 Unicode 的更多信息,请参见 这一页

(注意,所有 Java 字符都是 BMP 中的 UTF-16代码点; 要表示 U + FFFF 之上的字符,需要在 Java 中使用代理对。)

我相信在网络上有很多关于这方面的好文章,但是这里有一个简短的总结。

UTF-8和 UTF-16都是可变长度编码。然而,在 UTF-8中,一个字符可能至少占用8位,而在 UTF-16中,字符长度从16位开始。

UTF-8的主要优点:

  • 诸如数字、没有重音符号的拉丁字符等基本 ASCII 字符占用一个与 US-ASCII 表示相同的字节。这样,所有 US-ASCII 字符串都成为有效的 UTF-8,这在许多情况下提供了良好的向后兼容性。
  • 没有空字节,允许使用以空结尾的字符串,这也引入了大量的向后兼容性。
  • UTF-8与字节顺序无关,所以不必担心 Big Endian/Little Endian 问题。

UTF-8的主要缺点:

  • 许多常见字符的长度不同,这使得通过代码点进行索引和计算代码点数量的速度大大减慢。
  • 即使字节顺序并不重要,有时 UTF-8仍然有 BOM (字节顺序标记) ,用来通知文本是用 UTF-8编码的,即使文本只包含 ASCII 字符,也会破坏与 ASCII 软件的兼容性。微软软件(如记事本)特别喜欢将 BOM 添加到 UTF-8。

UTF-16的主要优点:

  • BMP (基本多语言平面)字符,包括拉丁文、西里尔字母、大多数中文(中国强制支持 BMP 以外的一些编码点) ,大多数日文可以用2字节表示。如果文本 没有包含补充字符,这将加速索引和计算代码点计数。
  • 即使文本有补充字符,它们仍然由一对16位值表示,这意味着总长度仍然可以被2整除,并且允许使用16位 char作为字符串的基本组成部分。

主要 UTF-16缺点:

  • US-ASCII 字符串中有大量空字节,这意味着没有以空结尾的字符串,并且浪费了大量内存。
  • 使用它作为固定长度的编码在许多常见的情况下“大多有效”(特别是在美国/欧盟/使用西里尔字母的国家/以色列/阿拉伯国家/伊朗和许多其他国家) ,经常导致支持中断。这意味着程序员必须注意代理对,并在重要的情况下正确处理它们!
  • 它的长度是可变的,因此计算或索引代码点的成本很高,尽管比 UTF-8低。

一般来说,UTF-16通常更适合于内存表示,因为 BE/LE 在那里是不相关的(只需使用本机顺序) ,而且索引更快(只是不要忘记正确处理代理对)。另一方面,UTF-8对于文本文件和网络协议非常有用,因为没有 BE/LE 问题,空终止通常很方便,而且具有 ASCII 兼容性。

这与 UTF-8/16无关(一般来说,尽管它确实可以转换为 UTF16,BE/LE 部分可以设置为 w/a 单行) ,但下面是将 String 转换为 byte []的最快方法。例如: 非常适合所提供的案例(哈希代码)。GetBytes (enc)相对较慢。

static byte[] toBytes(String s){
byte[] b=new byte[s.length()*2];
ByteBuffer.wrap(b).asCharBuffer().put(s);
return b;
}

区分 UTF-8和 UTF-16的简单方法是识别它们之间的共性。

除了为给定的字符共享相同的 Unicode 编号之外,每个字符都是它们自己的格式。

UTF-8试图表示,每个 Unicode 数字给予一个字节的字符(如果是 ASCII) ,其他2个字节,其他4个字节等等..。

UTF-16尝试表示,每个 Unicode 数字给出的字符以两个字节开始。如果两个字节不够,那么使用4个字节。如果这也不够,那么使用6字节。

从理论上讲,UTF-16的空间效率更高,但实际上 UTF-8的空间效率更高,因为处理的大多数字符(98% 的数据)是 ASCII,UTF-8尝试用单字节表示它们,而 UTF-16尝试用2字节表示它们。

而且,UTF-8是 ASCII 编码的超集。所以每个需要 ASCII 数据的应用程序都会被 UTF-8处理器接受。对 UTF-16来说,情况并非如此。UTF-16无法理解 ASCII,这是采用 UTF-16的一大障碍。

另一点需要注意的是,目前所有的 UNICODE 都可以适用于最大4字节的 UTF-8(考虑到世界上所有的语言)。这与 UTF-16相同,与 UTF-8(https://stackoverflow.com/a/8505038/3343801)相比没有真正节省空间

因此,人们尽可能地使用 UTF-8。

安全性: 仅使用 UTF-8

UTF-8和 UTF-16之间的区别? 我们为什么需要这些?

UTF-16的实现中,至少有两个安全漏洞。

WHATWG W3C现在宣布,只有 UTF-8可以在 Web 上使用。

这里列出的[安全]问题在完全使用 UTF-8时会消失,这是现在所有事情都必须进行编码的众多原因之一。

其他组织也这么说。

因此,尽管 UTF-16可能会继续被 Java 和 Windows 等一些系统内部使用,但是你可能在过去看到的 UTF-16在数据文件、数据交换等方面的极少使用可能会完全消失。