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();
我相信网上有很多关于这方面的好文章,但这里有一个简短的总结。
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 软件的兼容性. Microsoft 软件(如记事本)特别喜欢将 BOM 添加到 UTF-8。
主要的 UTF-16 优点:
BMP(基本多语言平面)字符,包括拉丁文、西里尔文、大多数中文(PRC 强制支持 BMP 之外的一些代码点),大多数日文可以用 2 个字节表示。如果文本不包含补充字符,这会加快索引和计算代码点计数。
即使文本有补充字符,它们仍然由成对的 16 位值表示,这意味着总长度仍然可以被 2 整除,并且允许使用 16 位 char 作为字符串的原始组件。
主要的 UTF-16 缺点:
US-ASCII 字符串中有很多空字节,这意味着没有以空结尾的字符串和大量浪费的内存。
在许多常见情况下(尤其是在美国/欧盟/使用西里尔字母的国家/以色列/阿拉伯国家/伊朗和许多其他国家)中,将其用作固定长度编码“大部分都有效”,通常会导致无法支持的地方中断支持。这意味着程序员必须了解代理对并在重要的情况下正确处理它们!
它是可变长度的,因此计数或索引代码点的成本很高,尽管低于 UTF-8。
一般来说,UTF-16 通常更适合内存中的表示,因为 BE/LE 在那里不相关(只使用本机顺序)并且索引更快(只是不要忘记正确处理代理对)。另一方面,UTF-8 非常适合文本文件和网络协议,因为不存在 BE/LE 问题,并且空终止通常会派上用场,而且兼容 ASCII。
它们只是表示 Unicode 字符的不同方案。
两者都是可变长度的 - UTF-16 对包含大多数常用字符的基本多语言平面 (BMP) 中的所有字符使用 2 个字节。
UTF-8 对 BMP 中的字符使用 1 到 3 个字节,对于当前 Unicode 范围 U+0000 到 U+1FFFFF 中的字符最多使用 4 个字节,并且如果有必要的话可以扩展到 U+7FFFFFFF...但值得注意的是,所有 ASCII 字符均以单个字节表示。
出于消息摘要的目的,您选择其中的哪一个并不重要,只要尝试重新创建摘要的每个人都使用相同的选项。
有关 UTF-8 和 Unicode 的更多信息,请参阅 this page。
(请注意,所有 Java 字符都是 BMP 中的 UTF-16 代码点;要表示 U+FFFF 以上的字符,您需要在 Java 中使用代理对。)
安全性:仅使用 UTF-8
UTF-8 和 UTF-16 的区别?为什么我们需要这些?
UTF-16 的实现中至少存在几个安全漏洞。见Wikipedia for details。
CVE-2008-2938
CVE-2012-2135
WHATWG 和 W3C 具有 now declared,只有 UTF-8 可以在 Web 上使用。
当专门使用 UTF-8 时,此处概述的 [安全] 问题就会消失,这是现在所有事物的强制编码的众多原因之一。
其他团体也这么说。
因此,虽然 UTF-16 可能会继续在 Java 和 Windows 等系统内部使用,但您过去可能在数据文件、数据交换等方面看到的 UTF-16 很少使用,可能会完全消失。
这与 UTF-8/16 无关(通常,虽然它确实转换为 UTF16 并且 BE/LE 部分可以用单行设置),但下面是将 String 转换为 byte[] 的最快方法。例如:完全适合所提供的情况(哈希码)。 String.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 尝试用一个字节(如果是 ASCII)来表示给字符的每个 unicode 数字,否则 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。
不定期副业成功案例分享