这是一个古老的问题,有许多好的答案,但有一件事应该补充。所有的答案都很笼统。我想补充的是BOM使用的例子,它们实际上造成了真正的问题,但是很多人并不知道。BOM破坏脚本shell脚本、Perl脚本、Python脚本、Ruby脚本、Node.js脚本或任何需要由解释器运行的其他可执行文件#!/bin/sh
#!/usr/bin/python
#!/usr/local/bin/perl
#!/usr/bin/env node它告诉系统在调用这样一个脚本时需要运行哪个解释器。如果脚本是用UTF-8编码的,人们可能会在一开始就尝试包括一个BOM。但实际上“#!”人物不仅仅是人物。他们实际上是幻数它恰好由两个ASCII字符组成。如果你把一些东西(如BOM)放在这些字符之前,那么文件看起来就像有一个不同的神奇数字,这可能会导致问题。Shebang字符由扩展的ASCII编码(包括UTF-8)中相同的两个字节表示,UTF-8通常用于当前类Unix系统上的脚本和其他文本文件。但是,utf-8文件可能以可选字节顺序标记(Bom)开头;如果“exec”函数专门检测字节0x23和0x21,则BOM(0xEF 0xBB 0xBF)的存在将阻止脚本解释器的执行。一些权威机构建议不要在POSIX(类Unix)脚本中使用字节顺序标记,[14]正是出于这个原因以及更广泛的互操作性和哲学考虑。此外,在UTF-8中,字节顺序标记是不必要的,因为编码不存在Endianness问题;它只用于将编码标识为UTF-8。[强调后加]BOM在JSON中是非法的实现不能在JSON文本的开头添加字节顺序标记。BOM在JSON中是多余的不仅是非法在JSON中,它也是不需要确定字符编码,因为有更可靠的方法可以明确地确定任何JSON流中使用的字符编码和endiannessBOM破坏JSON解析器不仅是非法在JSON和不需要,实际上破坏所有软件中显示的方法来确定编码。确定JSON的编码和endianness,检查NUL字节的前4个字节:00 00 00 xx - UTF-32BE
00 xx 00 xx - UTF-16BE
xx 00 00 00 - UTF-32LE
xx 00 xx 00 - UTF-16LE
xx xx xx xx - UTF-8现在,如果文件以BOM开头,则如下所示:00 00 FE FF - UTF-32BE
FE FF 00 xx - UTF-16BE
FF FE 00 00 - UTF-32LE
FF FE xx 00 - UTF-16LE
EF BB BF xx - UTF-8请注意:utf-32be不会以三个空开始,因此不会被识别。UTF-32LE第一个字节后面没有3个空号,因此不会被识别。在前4个字节中,utf-16be只有一个NUL,因此不会被识别。在前4个字节中,utf-16 le只有1个nul,因此不会被识别。根据实施情况,所有这些可能被错误地解释为UTF-8,然后被误解或拒绝为无效的UTF-8,或者根本不被承认。此外,如果像我建议的那样对有效的JSON进行实现测试,它甚至会拒绝输入,因为它不会像RFC那样以ASCII字符<128开头,因为输入确实编码为UTF-8。其他数据格式JSON中的BOM是不需要的,是非法的,并且破坏了根据RFC正确工作的软件。如果当时不使用JSON应该是个不需要考虑的问题,然而,总是有人坚持使用Boms、注释、不同的引用规则或不同的数据类型来破坏JSON。当然,如果需要的话,任何人都可以自由地使用Boms之类的东西-只是不要叫它JSON。对于JSON以外的其他数据格式,请查看它的真实外观。如果唯一的编码是UTF-*,并且第一个字符必须是小于128的ASCII字符,那么您已经有了确定数据编码和编码的所有信息。即使将Boms添加为可选功能,也只会使其更加复杂和容易出错。BOM的其他用途至于JSON或脚本之外的使用,我认为这里已经有了非常好的答案。我想添加更多关于脚本和序列化的详细信息,因为这是BOM字符导致实际问题的一个例子。