引言 为什么需要 UTF-8?
在计算机世界中,字符编码是连接人类语言与机器逻辑的桥梁。早期的 ASCII
编码仅支持英文字符,而 Unicode
的诞生解决了多语言兼容性问题。然而,Unicode
的定长编码(如 UTF-16 需 2-4 字节)在存储和传输效率上存在缺陷。UTF-8
作为Unicode
的变长编码方案
,巧妙平衡了兼容性、灵活性与效率,成为互联网上最广泛使用的编码标准。
一、UTF-8 编码简介
以下是 UTF-8 编码中汉字的对应关系及编码规则详解,结合 Unicode 码位与二进制转换逻辑:
1. UTF-8 编码规则
UTF-8 是 Unicode 的变长编码方案,通过 首字节标识符 确定字符总长度:
Unicode 码位范围 | UTF-8 字节数 | 首字节格式 | 后续字节格式 |
---|---|---|---|
U+0000 – U+007F | 1 字节 | 0xxxxxxx | 无 |
U+0080 – U+07FF | 2 字节 | 110xxxxx 10xxxxxx | 每个后续字节为 10xxxxxx |
U+0800 – U+FFFF | 3 字节 | 1110xxxx 10xxxxxx 10xxxxxx | 同上 |
U+10000 – U+10FFFF | 4 字节 | 11110xxx 10xxxxxx ×3 | 同上 |
2. 汉字在 UTF-8 中的编码
(1) Unicode 码位范围
-
基本多文种平面(BMP):
汉字主要分布在 U+4E00 – U+9FFF(常用汉字)和 U+3400 – U+4DBF(扩展 A 区)等区域。 -
辅助平面:
极少数生僻字可能位于 U+20000 – U+2A6DF(扩展 B 区)等,需 4 字节编码。
(2) 3 字节编码示例
以汉字 “汉” 为例,UTF-8 转换步骤:
1. Unicode 码位转二进制
- 十六进制:
U+6C49
- 二进制分解(按 Unicode 标准的 16 位表示):
6 | C | 4 | 9 |
---|---|---|---|
0110 | 1100 | 0100 | 1001 |
注意:实际编码时需将高位补零至 16 位,即 0110 1100 0100 1001。
2. 确定 UTF-8 编码模板
根据 Unicode 码位范围 U+0800 – U+FFFF,使用 3 字节模板
:
1110xxxx 10xxxxxx 10xxxxxx
总位数:3 字节 × 8 位 = 24 位
- 填充规则:
- 第一个字节的 xxxx 占高位 4 位
- 后续每个字节的 xxxxxx 占 6 位
3. 二进制位填充模板
将二进制 0110 1100 0100 1001 按从高位到低位的顺序填充到模板中:
-
第一个字节:
取前 4 位 0110 → 填充到 1110xxxx 的 xxxx 位置
完整字节:1110 0110(即 E6) -
第二个字节:
取后续 6 位 110001 → 填充到 10xxxxxx 的 xxxxxx 位置
完整字节:10 110001(即 B1) -
第三个字节:
取剩余 6 位 01001001 → 填充到 10xxxxxx 的 xxxxxx 位置
完整字节:10 001001(即 89) -
填充后的二进制序列:
1110 0110 1011 0001 1000 1001
4. 二进制转十六进制
将每个字节的 8 位二进制转换为十六进制:
二进制 | 十六进制 |
---|---|
1110 0110 | E6 |
1011 0001 | B1 |
1000 1001 | 89 |
最终 UTF-8 编码:E6 B1 89
(3) 4 字节编码示例
以汉字 “𠮷”(U+20BB7)为例:
- Unicode 码位:U+20BB7 → 二进制:0010 0000 1011 1011 0111
- UTF-8 转换:F0 A0 AE B7
3. 常见汉字 UTF-8 编码对照
汉字 | Unicode 码位 | UTF-8 十六进制 | 二进制表示 |
---|---|---|---|
一 | U+4E00 | E4 B8 80 | 11100100 10111000 10000000 |
丁 | U+4E01 | E4 B8 81 | 11100100 10111000 10000001 |
万 | U+4E07 | E4 B8 87 | 11100100 10111000 10000111 |
上 | U+4E0A | E4 B8 8A | 11100100 10111000 10001010 |
东 | U+4E1C | E4 B8 9C | 11100100 10111000 10011100 |
4. 编码特性与优势
-
兼容 ASCII:
ASCII 字符(如英文字母、数字)与 UTF-8 完全一致,无需转换。 -
错误容错:
若传输中丢失一个字节,可通过首字节标识符快速定位错误范围,避免影响后续字符解析。 -
变长灵活性:
ASCII 用 1 字节,汉字用 3 字节,生僻字用 4 字节,平衡存储与效率。
5. 与其他编码的对比
编码方式 | 字节数 | 兼容性 | 应用场景 |
---|---|---|---|
UTF-8 | 3 字节 | 全平台兼容 | 网页、API、国际化 |
GBK | 2 字节 | 仅兼容中文 | 旧版中文软件 |
GB18030 | 2/4 字节 | 强制国家标准 | 政府、金融系统 |
6. 编码验证方法
通过 Java 代码验证汉字编码:
public class Utf8Test {
public static void main(String[] args) {
String hanzi = "汉";
byte[] utf8Bytes = hanzi.getBytes(StandardCharsets.UTF_8);//值为 [-26, -79, -119]
System.out.println("Hex: " + bytesToHex(utf8Bytes)); // 输出: E6 B1 89
}
/** 格式化字节数组转十六进制字符串 */
private static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02X ", b));//格式化字节数组转十六进制字符串
}
return sb.toString().trim();
}
}
打印结果如下:
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
Hex: E6 B1 89
二、UTF-8 应用实践
1. HTTP 请求阶段的数据格式处理
- 应用场景:传输文本数据(如 JSON、XML、HTML 等)。
- 实现方法:
- 请求头设置:通过 Content-Type 指定编码格式(如 text/plain; charset=UTF-8)。
- 数据转换:使用 String 类直接构造请求体,或通过 getBytes(“UTF-8”) 将字符串转为字节数组。
HTTP 请求示例代码:
//json 格式数据
String jsonBody = "{\"name\":\"张三\", \"age\":30}";
//转为 UTF-8 格式字节数组
byte[] data = jsonBody.getBytes(StandardCharsets.UTF_8);
// 创建 Http 连接请求并发送数据
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.getOutputStream().write(data);
我们写测试类打印 经过 UTF-8 编码后的 data 的 十六进制字符串
数据:
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
Hex: 7B 22 6E 61 6D 65 22 3A 22 E5 BC A0 E4 B8 89 22 2C 20 22 61 67 65 22 3A 33 30 7D
参考资料
附录
附加信息或补充说明。
版权声明: 本文由 [dazhong2012] 创作,采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处。