编码基础
→ 返回计算机基础
位、字节、字符
1 bit(位) = 0 或 1,计算机最小存储单元
8 bit = 1 Byte(字节),最小寻址单元
1 KB = 1024 Byte
1 MB = 1024 KB
1 GB = 1024 MB
字符 ≠ 字节:字符是人类可读的符号,字节是存储单位,一个字符占几个字节取决于编码方式。
常见编码
ASCII
- 范围:128个字符(英文字母、数字、符号、控制字符)
- 每个字符 1字节,只用低7位,最高位为0
'A'= 65 =0100 0001
GBK / GB2312
- 中国国家标准,向下兼容 ASCII
- ASCII字符:1字节
- 汉字:2字节
'中'=0xD6 0xD0(两个字节)
IBM EBCDIC 系列
IBM 大型机(Mainframe)使用的私有编码体系,与 ASCII 不兼容。
EBCDIC(Extended Binary Coded Decimal Interchange Code):IBM 1964 年推出,字母 A-Z 不连续排列,与 ASCII 字节值完全不同。
常见 EBCDIC 代码页:
| 代码页 | 名称 | 覆盖范围 |
|---|---|---|
| IBM037 | EBCDIC 美国英语 | 英文、基本符号 |
| IBM500 | EBCDIC 多语言 | 西欧语言 |
| IBM935 | EBCDIC 简体中文 | 英文 + 简体汉字(双字节) |
| IBM937 | EBCDIC 繁体中文 | 英文 + 繁体汉字(双字节) |
| IBM939 | EBCDIC 日语 | 英文 + 日语(双字节) |
IBM935 结构:
单字节部分:EBCDIC 编码的英文、数字、符号(1字节)
双字节部分:DBCS(Double Byte Character Set)汉字(2字节)
IBM935 是 SBCS + DBCS 混合编码,用移位字符(Shift-In/Shift-Out)区分单双字节区域:
0x0E → Shift-Out,后续字节按双字节解析
0x0F → Shift-In,回到单字节 EBCDIC 模式
例:IBM935 与 GBK 同样覆盖简体中文,但字节映射完全不同,两者不可混用。
应用场景:银行、证券、保险等行业的 IBM 大型机系统(z/OS、AS/400),数据交换时需明确指定代码页做转码。
Unicode
Unicode 是字符集,不是编码,给全球所有字符分配唯一码点(Code Point)。
例如:'中' 的码点是 U+4E2D
具体怎么存储由编码方案决定(UTF-8、UTF-16、UTF-32)。
UTF-8(最主流)
变长编码,1~4字节:
| 字符范围 | 字节数 | 说明 |
|---|---|---|
| U+0000 ~ U+007F | 1字节 | ASCII,完全兼容 |
| U+0080 ~ U+07FF | 2字节 | 拉丁文、希腊文、阿拉伯文等 |
| U+0800 ~ U+FFFF | 3字节 | 中文、日文、韩文(CJK) |
| U+10000 ~ U+10FFFF | 4字节 | 生僻字、emoji(😊) |
英文 'A' → 1字节:0x41
中文 '中' → 3字节:0xE4 0xB8 0xAD
emoji '😊' → 4字节:0xF0 0x9F 0x98 0x8A
UTF-8 编码规则:
1字节:0xxxxxxx
2字节:110xxxxx 10xxxxxx
3字节:1110xxxx 10xxxxxx 10xxxxxx
4字节:11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
以 '中'(U+4E2D = 0100 1110 0010 1101)为例:
填入3字节模板:1110xxxx 10xxxxxx 10xxxxxx
11100100 10111000 10101101
= 0xE4 0xB8 0xAD
UTF-16
- BMP(基本多文种平面,U+0000~U+FFFF):2字节(包含绝大多数常用汉字)
- 辅助平面:4字节(代理对)
- Java 内部
char用的是 UTF-16,所以char占 2 字节 - 有大端(UTF-16 BE)和小端(UTF-16 LE)之分,文件头用 BOM 区分
UTF-32
- 所有字符固定 4字节
- 空间浪费,几乎不用于存储和传输
- 优点是随机访问简单(第n个字符直接偏移 4n)
编码对比
| 编码 | 英文 | 汉字 | 特点 |
|---|---|---|---|
| ASCII | 1字节 | 不支持 | 最古老,英文专用 |
| GBK | 1字节 | 2字节 | 中文环境遗留标准 |
| IBM935 | 1字节(EBCDIC) | 2字节(DBCS) | IBM大型机简体中文,与ASCII不兼容 |
| UTF-8 | 1字节 | 3字节 | 互联网标准,兼容ASCII |
| UTF-16 | 2字节 | 2字节 | Java内部、Windows内部 |
| UTF-32 | 4字节 | 4字节 | 定长,浪费空间 |
常见乱码场景
| 场景 | 原因 | 解决 |
|---|---|---|
| 页面中文乱码 | 响应编码未指定 | response.setCharacterEncoding("UTF-8") |
| 读文件乱码 | 文件编码与读取编码不符 | 明确指定 new InputStreamReader(in, "UTF-8") |
| MySQL 乱码 | 字符集不是 utf8mb4 | 建表和连接都用 utf8mb4 |
| URL 参数乱码 | GET 参数编码问题 | URLEncoder.encode(s, "UTF-8") |
BOM(Byte Order Mark)
UTF-8 文件有时带 BOM(0xEF 0xBB 0xBF),Linux 环境建议保存为 UTF-8 without BOM。