[NodeJs系列]聊一聊BOM
最近在看Node源码的时候,偶然间,看到如下函数:
/**
* Remove byte order marker. This catches EF BB BF (the UTF-8 BOM)
* because the buffer-to-string conversion in `fs.readFileSync()`
* translates it to FEFF, the UTF-16 BOM.
*/
function stripBOM(content) {
if (content.charCodeAt(0) === 0xFEFF) {
content = content.slice(1);
}
return content;
}
对于函数的功能,注释写的很清楚了-用于清除字节序标识符(BOM)。
对于BOM,相信大多数人对其即陌生又熟悉,我们在各大IDE中常常见到它的身影,但要真的把它解释清除,却有点力不从心。故此,笔者利用闲暇之余搜索资料整理成文,如果错漏,还望提点!
字节序
在解释BOM之前,我们不得不提到字节序。
在古时,我们的很多书刊保有从左到右的排版的习惯。即使是今天,某些国家的文字读序依旧存在差异。计算机世界也是如此。
我们把多字节排练的顺序叫做字节序。
这里我们通过一个例子展开说明(本例来自:“字节序”是个什么鬼?):
给定两个分别需要4个字节存储的整数,为了方便说明,使用16进制表示这两个数,即0x12345678和0x11223344。对于如何存储,有人提了两个方案:
方案一:
方案二:
对于方案一,高位字节在存储在高位地址,低位字节在低位地址,我们称之为大端(Big endian)字节序。方案二把低位字节在前,高位字节在后,我们把这种顺序叫做小端(Little endian)字节序。
BOM
对于人类而言,字节序也许并不是问题。比如从右往左读"字节序",聪明如你们,会发现“序节字”根本语义不通,可以轻松的找到解决之道。但对于计算机而言,它不明白什么是语义,也没法联系上下文。它只能按照给定的指令去读取字节。如果是大端字节序,先读到的就是高位字节,后读到的就是低位字节。小端字节序正好相反。
所以对于计算机而言,我们需要一种方法去标识字节序,以防乱码的出现。BOM就是一种用于标识的unicode字符,它常被用来当做标示以UTF-8、UTF-16或UTF-32为编码的文件
对于UTF-16和UTF-32而言,因为他们分别使用2个字节和4个字节编码Unicode字符,对于多字节编码,BOM的存在显然很有必要。此时BOM被放置为文件或字符串流的第一个字符,如果标识符为U+FFFE
则表示大端字节序,如果标识符为U+FEFF
则表示小端字节序。
那既然BOM是用于标示字节序的,那为什么还要把它删除呢?这里就不得不提一下UTF-8了。
UTF-8是一种可变字节长度的编码方式(最小1字节,最大4字节),也就是说UTF-8可以根据数据大小来决定要存储的字节数。它的编码方式与其他两者不同,无需使用BOM。
UTF-8在首字节标识了字节的个数。如果首字节以0开头,则代表单字节编码,如果以110开头者表示该字节为两个字节中的第一个字节,以此类推。除了单字节外,多字节UTF-8码的后续字节均以10开头。
所以1~4字节UTF-8编码看起来是这样的:
0xxxxxxx
110xxxxx 10xxxxxx
1110xxxx 10xxxxxx 10xxxxxx
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
```
So BOM 在UTF-8编码中是非必须的,在类Unix系统(大量使用文本文件,用于文件格式,用于进程间通信)中,这种做法(插入BOM)是不被建议采用,因为它会妨碍到如解译器脚本开头的Shebang等的正确处理,但是许多视窗程序(包含记事本)会需要添加字节顺序标记到UTF-8文件。
参考