在不同的编码格式之间进行转换的时候,我们经常会看到UTF-8 without BOM、big endian、little endian之类的字眼,它们是什么意思呢?
这些词都和计算机储存数据的顺序有关。计算机一般以字节(也就是两个十六进制位)为单位储存数据。然而,如果某个数据块要占据多个字节,数据块内部该按什么顺序存放这些字节呢?举个例子,汉字“乙”的Unicode码位为4E59。如果把4E59视为一个数据块的话,“乙”字的两个编码究竟该用4E 59还是59 4E呢?这对我们人来说也许压根不是个问题,当然该用4E59了。可是对于计算机而言却并不那么绝对,将数据abcd在内部表示为dcba的形式是很有好处的(比如类型recast的时候不需要做调整)。
总而言之,对于多字节数据块而言,先储存头还是先储存尾,这是个问题。两种方式各有其合理之处,在实际的应用中也同时存在着。为了区别这两种方式,人们从《格列佛游记》中借用了“endian”这个词。故事中小人国的内战是源于吃鸡蛋时是究竟从大头(big endian)敲开还是从小头(little endian)敲开。计算机学者(最早是Danny Cohen)模仿这种命名方式,将最高位放在开头的储存顺序称为big endian,将最低位放在开头的称为little endian。
回到汉字编码,UTF-16的最小单位(也就是上文的数据块)是16个bit,也就是1个字节,所以面临着big endian和little endian的选择问题。为了标明一个UTF-16文件使用的是little endian还是big endian,在文件最开头的地方设置了一个BOM(byte order mask)。这样软件对文件进行读取的时候就不会出错。
UTF-8由于最小编码单位是8个bit,也就是1个字节,所以不存在endianness的问题,不需要在文件开头设置BOM。不过,为UTF-8文件设置BOM也是允许的,可以用来说明“本文件的编码格式是UTF-8编码”。因此,UTF-8就往往有with/without BOM两种选择了。