当前位置 博文首页 > 小龙狗的博客:字节序Endian与字节序标记BOM详解
问:UTF-8 和 UTF-8-BOM 有啥区别?
我们用 Python 演示一下,带与不带 BOM 的字符串有啥区别。
if __name__ == '__main__':
str = '你好啊树哥'
print('str:', str)
str_encode_utf8 = str.encode('utf-8')
print('str_encode_utf8:', str_encode_utf8)
str_encode_utf8_bom = str.encode('utf-8-sig')
print('str_encode_utf8_bom:', str_encode_utf8_bom)
输出结果显示,带 BOM 的比不带的文本在开头多了 ef bb bf
几个字节,为什么是这样?它有什么用呢?
str: 你好啊树哥
str_encode_utf8: b'\xe4\xbd\xa0\xe5\xa5\xbd\xe5\x95\x8a\xe6\xa0\x91\xe5\x93\xa5'
str_encode_utf8_bom: b'\xef\xbb\xbf\xe4\xbd\xa0\xe5\xa5\xbd\xe5\x95\x8a\xe6\xa0\x91\xe5\x93\xa5'
BOM 全称 Byte Order Mark,字节顺序标记的意思,今天我们就来详细聊聊它。
字节序(Endian),就是字节顺序(Byte-Order),还叫端序或尾序(Endianness)。描述的是计算机对 多字节数据 存储和传输时字节的顺序。因为单字节的数据只需要读取一个字节,没有字节序说法。
字节序分为两种排列模式,分别是大端字节序和小端字节序。
例如有 0x1234abcd
将它写入到以 0x0000
开始的内存中。
内存地址 | 0x0000 | 0x0001 | 0x0002 | 0x0003 |
---|---|---|---|---|
Big-endian | 0x12 | 0x34 | 0xab | 0xcd |
Little-endian | 0xcd | 0xab | 0x34 | 0x12 |
计算机默认都是从低位开始读,所以计算机内部处理都是小端字节序。但人类习惯读写大端字节序,所以除了计算机的内部处理,其他的应用场合几乎都是大端字节序,比如网络传输和文件存储。
BOM,全称 Byte Order Mark,字节顺序标记。出现在文本文件头部,用于标识文件是采用哪种格式的编码。
由于 FEFF
和 FFFE
在 UCS 编码表中不存在(也就是说它无实际意义),因此在字节流传输过程中可以利用它们打头来说明字节序。
FEFF
开通的字节流,就表明这是 Big-Endian 的;FFFE
就表明这个字节流是 Little- Endian 的。像 FEFF
和 FFFE
这种就称作 Zero Width No-Break Space,翻译过来就是 零宽无间断间隔 ,这个字符就是所谓的 BOM。下面是不同编码的字节顺序标记表示。
编码 | 表示 |
---|---|
UTF-8 | EF BB BF |
UTF-16 (大端序) | FE FF |
UTF-16(小端序) | FF FE |
UTF-32 (大端序) | 00 00 FE FF |
UTF-32 (小端序) | FF FE 00 00 |
总结几点注意事项。
EF BB BF
开头的字节流,就知道这是 UTF-8编码了。U+FEFF
出现在开头就是标识该字节流的字节序,如果出现在字节流的中间则表达零宽度非换行空格的意义,用户看起来就是一个空格。从 Unicode 3.2 开始,U+FEFF
只能出现在字节流的开头用于标识字节序。取而代之的是,使用 U+2060
来表达零宽度无断空白。U+FEFF
是代码点,抽象性质的。而 EF BB BF
,FE FF
,00 00 FE FF
则是在不同编码方案下的具体表现形式。这是概念性的问题。参考了
[1]. Endian
https://www.jianshu.com/p/a348f8fc9fc9
[2]. BOM (字节顺序标记(ByteOrderMark))
https://baike.baidu.com/item/BOM/2790364?fr=aladdin
[3]. 字节顺序标记(BOM)详解
https://blog.csdn.net/gufenchen/article/details/90552774
[4]. 「带 BOM 的 UTF-8」和「无 BOM 的 UTF-8」有什么区别?网页代码一般使用哪个?
https://www.zhihu.com/question/20167122