字节序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)。描述的是计算机对 多字节数据 存储和传输时字节的顺序。因为单字节的数据只需要读取一个字节,没有字节序说法。

字节序分为两种排列模式,分别是大端字节序和小端字节序。

  • 大端(Big-endian):高位字节数据存放在内存低地址处,低位字节数据存放在内存高地址处。大端模式比较符合人类的阅读习惯,也这是人类读写数值的方式。
  • 小端(Little-endian):高位字节数据存放在内存高地址处,低位字节数据存放在内存低地址处。由于计算机内存数据处理是从低位开始的,因为小端模式更加符合计算机的处理方式。

例如有 0x1234abcd 将它写入到以 0x0000 开始的内存中。

内存地址0x00000x00010x00020x0003
Big-endian0x120x340xab0xcd
Little-endian0xcd0xab0x340x12

计算机默认都是从低位开始读,所以计算机内部处理都是小端字节序。但人类习惯读写大端字节序,所以除了计算机的内部处理,其他的应用场合几乎都是大端字节序,比如网络传输和文件存储。

  • 主机字节序,Host Byte Order, HBO。指机器的字节序,有大端和小端模式,由机器的CPU处理器的处理决定,小端模式较为常见。
  • 网络字节序,Network Byte Order, NBO。是TCP/IP中规定好的一种数据表示格式,网络字节序采用 Big Endian 排列按照从高到低的顺序存储,在网络上使用统一的网络字节顺序可以避免兼容性问题。TCP/IP中规定好了一种数据表示格式,与具体的CPU类型、操作系统等无关,从而保证数据在不同主机之间传输时能够被正确解释。

字节序标记

BOM,全称 Byte Order Mark,字节顺序标记。出现在文本文件头部,用于标识文件是采用哪种格式的编码。

由于 FEFFFFFE 在 UCS 编码表中不存在(也就是说它无实际意义),因此在字节流传输过程中可以利用它们打头来说明字节序。

  • 如果接收者收到以 FEFF 开通的字节流,就表明这是 Big-Endian 的;
  • 如果收到 FFFE 就表明这个字节流是 Little- Endian 的。

FEFFFFFE 这种就称作 Zero Width No-Break Space,翻译过来就是 零宽无间断间隔 ,这个字符就是所谓的 BOM。下面是不同编码的字节顺序标记表示。

编码表示
UTF-8EF BB BF
UTF-16 (大端序)FE FF
UTF-16(小端序)FF FE
UTF-32 (大端序)00 00 FE FF
UTF-32 (小端序)FF FE 00 00

总结几点注意事项。

  • UTF-8 本身不需要 BOM ,但可以使用它。UTF-8 始终是相同的字节顺序,BOM 仅用于表明编码方式。如果接收者收到以 EF BB BF 开头的字节流,就知道这是 UTF-8编码了。
  • 以前字符 U+FEFF 出现在开头就是标识该字节流的字节序,如果出现在字节流的中间则表达零宽度非换行空格的意义,用户看起来就是一个空格。从 Unicode 3.2 开始,U+FEFF 只能出现在字节流的开头用于标识字节序。取而代之的是,使用 U+2060 来表达零宽度无断空白。
  • 刚刚说到的 U+FEFF 是代码点,抽象性质的。而 EF BB BFFE FF00 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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值