当前位置 博文首页 > 小龙狗的博客:字节序Endian与字节序标记BOM详解

    小龙狗的博客:字节序Endian与字节序标记BOM详解

    作者:[db:作者] 时间:2021-07-09 21:56

    问题引入

    问: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

    cs