提问人:simple 提问时间:2/9/2010 最后编辑:TylerHsimple 更新时间:9/21/2023 访问量:865999
UTF-8 和带 BOM 的 UTF-8 有什么区别?
What's the difference between UTF-8 and UTF-8 with BOM?
答:
没有 BOM 的 UTF-8 没有 BOM,这并不比有 BOM 的 UTF-8 更好,除非文件的使用者需要知道(或从知道中受益)文件是否是 UTF-8 编码。
BOM 通常可用于确定编码的字节序,这在大多数用例中不是必需的。
此外,对于那些不了解或不关心它的消费者来说,BOM 可能是不必要的噪音/痛苦,并可能导致用户混淆。
评论
来自 http://en.wikipedia.org/wiki/Byte-order_mark:
字节顺序标记 (BOM) 是 Unicode 用于表示 文本文件的字节序(字节顺序) 或流。它的代码点是 U+FEFF。 BOM 的使用是可选的,如果使用, 应出现在文本的开头 流。除了其作为 字节顺序指示器,BOM 字符还可以指示以下哪一个 几种 Unicode 表示形式 文本被编码。
始终在文件中使用 BOM 将确保它始终在支持 UTF-8 和 BOM 的编辑器中正确打开。
我没有 BOM 的真正问题如下。假设我们有一个文件,其中包含:
abc
如果没有 BOM,这在大多数编辑器中将作为 ANSI 打开。因此,此文件的另一个用户打开它并附加一些本机字符,例如:
abg-αβγ
哎呀。。。现在文件仍在 ANSI 中,你猜怎么着,“αβγ”不占用 6 个字节,而是 3 个字节。这不是 UTF-8,这会导致开发链后期出现其他问题。
评论
UTF-8 BOM 是文本流 () 开头的字节序列,允许读者更可靠地猜测文件是否以 UTF-8 编码。0xEF, 0xBB, 0xBF
通常,BOM 用于表示编码的字节序,但由于字节序与 UTF-8 无关,因此不需要 BOM。
根据 Unicode 标准,不建议使用 UTF-8 文件的 BOM:
2.6 编码方案
...对于 UTF-8,既不需要也不建议使用 BOM,但在 UTF-8 数据从使用 BOM 的其他编码形式转换而来或将 BOM 用作 UTF-8 签名的上下文中可能会遇到这种情况。有关更多信息,请参见第 16.8 节 “特殊”中的“字节顺序标记”小节。
评论
引用于BOM的维基百科页面底部:http://en.wikipedia.org/wiki/Byte-order_mark#cite_note-2
“对于 UTF-8,既不需要也不建议使用 BOM,但在 UTF-8 数据从使用 BOM 的其他编码形式转换而来或将 BOM 用作 UTF-8 签名的上下文中可能会遇到”
评论
其他优秀的答案已经回答了:
- UTF-8 和 BOM 版本的 UTF-8 之间没有官方区别
- BOM 版本的 UTF-8 字符串将从以下三个字节开头。
EF BB BF
- 从文件/流中提取字符串时,必须忽略这些字节(如果存在)。
但是,作为附加信息,如果字符串是用 UTF-8 编码的,UTF-8 的 BOM 可能是一种“闻到”的好方法......或者它可以是任何其他编码中的合法字符串......
例如,数据 [EF BB BF 41 42 43] 可以是:
- 合法的 ISO-8859-1 字符串“ABC”
- 合法的 UTF-8 字符串“ABC”
因此,虽然通过查看第一个字节来识别文件内容的编码可能很酷,但您不应该依赖它,如上面的示例所示
编码应该是已知的,而不是占卜的。
评论
UTF-8 和没有 BOM 的 UTF-8 有什么区别?
简短的回答:在 UTF-8 中,BOM 被编码为文件开头的字节。EF BB BF
长答案:
最初,人们期望Unicode将采用UTF-16 / UCS-2编码。BOM 是针对此编码形式设计的。当您有 2 字节代码单元时,必须指示这两个字节的顺序,执行此操作的常见约定是在数据开头包含字符 U+FEFF 作为“字节顺序标记”。字符 U+FFFE 是永久未分配的,因此它的存在可用于检测错误的字节顺序。
无论平台字节序如何,UTF-8 都具有相同的字节顺序,因此不需要字节顺序标记。但是,它可能(作为字节序列)出现在从 UTF-16 转换为 UTF-8 的数据中,或者作为“签名”来指示数据是 UTF-8。EF BB FF
哪个更好?
没有。正如马丁·科特(Martin Cote)所回答的那样,Unicode标准不推荐它。它会导致非 BOM 感知软件出现问题。
检测文件是否为 UTF-8 的更好方法是执行有效性检查。UTF-8 对哪些字节序列是有效的有严格的规定,因此误报的概率可以忽略不计。如果字节序列看起来像 UTF-8,那么它可能是。
评论
sh
perl
g++
BOM 倾向于在某个地方、某个地方蓬勃发展(没有双关语(原文如此))。当它蓬勃发展时(例如,浏览器、编辑器等无法识别),它会在文档开头显示为奇怪的字符(例如,HTML 文件、JSON 响应、RSS 等),并导致尴尬,例如最近在奥巴马在 Twitter 上谈论时遇到的编码问题。
当它出现在难以调试的地方或忽略测试时,这是非常烦人的。因此,除非您必须使用它,否则最好避免使用它。
评论
我从不同的角度来看待这个问题。我认为带有 BOM 的 UTF-8 更好,因为它提供了有关文件的更多信息。只有当遇到问题时,我才使用不带 BOM 的 UTF-8。
我在我的页面上使用了多种语言(甚至是西里尔文)很长时间了,当文件在没有 BOM 的情况下保存并且我重新打开它们以使用编辑器进行编辑时(正如 cherouvim 也指出的那样),一些字符已损坏。
请注意,当您尝试使用 UTF-8 编码保存新创建的文件时,Windows 的经典记事本会自动使用 BOM 保存文件。
我个人保存带有 BOM 的服务器端脚本文件(.asp、.ini、.aspx 和没有 BOM 的 .html 文件。
评论
chcp 65001
type myfile
echo aaa>a.a
echo אאא>a.a
带有 BOM 的 UTF-8 可以更好地识别。我艰难地得出了这个结论。我正在做一个项目,其中一个结果是一个CSV文件,包括Unicode字符。
如果保存的 CSV 文件没有 BOM,Excel 会认为它是 ANSI 并显示乱码。在前面添加“EF BB BF”后(例如,使用带有 UTF-8 的记事本重新保存它;或使用 UTF-8 的记事本++)重新保存它,Excel 可以正常打开它。
RFC 3629 建议在 Unicode 文本文件前面加上 BOM 字符:“UTF-8,ISO 10646 的转换格式”,2003 年 11 月 在 https://www.rfc-editor.org/rfc/rfc3629 (最后的信息可在以下位置找到: http://www.herongyang.com/Unicode/Notepad-Byte-Order-Mark-BOM-FEFF-EFBBBF.html)
评论
当您想要显示以 UTF-8 编码的信息时,您可能不会遇到问题。例如,将 HTML 文档声明为 UTF-8,您将在浏览器中显示文档正文中包含的所有内容。
但是,当我们在 Windows 或 Linux 上拥有文本、CSV 和 XML 文件时,情况并非如此。
例如,Windows 或 Linux 中的文本文件,这是可以想象的最简单的事情之一,它不是(通常)UTF-8。
将其另存为 XML 并将其声明为 UTF-8:
<?xml version="1.0" encoding="UTF-8"?>
它不会正确显示(不会被读取),即使它被声明为 UTF-8。
我有一串包含法语字母的数据,需要将其保存为 XML 以进行联合。无需从一开始就创建 UTF-8 文件(更改 IDE 中的选项和“创建新文件”)或在文件开头添加 BOM
$file="\xEF\xBB\xBF".$string;
我无法将法语字母保存在XML文件中。
评论
将 BOM 放入 UTF-8 编码文件中至少存在三个问题。
- 不包含文本的文件不再是空的,因为它们始终包含 BOM。
- 在 UTF-8 的 ASCII 子集中保存文本的文件本身不再是 ASCII,因为 BOM 不是 ASCII,这使得一些现有工具崩溃,用户可能无法替换此类旧工具。
- 无法将多个文件连接在一起,因为每个文件现在的开头都有一个 BOM。
而且,正如其他人所提到的,拥有 BOM 来检测某些东西是 UTF-8 既不充分也不必要:
- 这还不够,因为任意字节序列可能恰好以构成 BOM 的确切序列开头。
- 这不是必需的,因为您可以像读取 UTF-8 一样读取字节;如果成功,根据定义,它是有效的 UTF-8。
评论
cat
cat
cat
如果您在 HTML 文件中使用 UTF-8,并且在同一页面上使用塞尔维亚语西里尔文、塞尔维亚拉丁语、德语、匈牙利语或一些外来语言,则带有 BOM 的 UTF 会更好。
这是我的观点(30 年的计算和 IT 行业)。
评论
<meta http-equiv
如上所述,带有 BOM 的 UTF-8 可能会导致非 BOM 感知(或兼容)软件出现问题。我曾经使用基于 Mozilla 的 KompoZer 编辑编码为 UTF-8 + BOM 的 HTML 文件,因为客户需要所见即所得的程序。
保存时布局总是会被破坏。我花了一些时间来解决这个问题。这些文件在Firefox中运行良好,但在Internet Explorer中再次显示出CSS怪癖,破坏了布局。在摆弄了几个小时的链接的CSS文件无济于事后,我发现Internet Explorer不喜欢BOMfed HTML文件。再也不会了。
另外,我刚刚在维基百科上找到了这个:
shebang 字符在扩展的 ASCII 编码中由相同的两个字节表示,包括 UTF-8,UTF-8 通常用于当前类 Unix 系统上的脚本和其他文本文件。但是,UTF-8 文件可能以可选的字节顺序标记 (BOM) 开头;如果“exec”函数专门检测到字节0x23 0x21,则 shebang 之前存在 BOM (0xEF 0xBB 0xBF) 将阻止脚本解释器的执行。一些权威人士建议不要在POSIX(类Unix)脚本中使用字节顺序标记[15],因为这个原因以及更广泛的互操作性和哲学问题
一个实际的区别是,如果你为 Mac OS X 编写一个 shell 脚本并将其保存为纯 UTF-8,你会得到响应:
#!/bin/bash: No such file or directory
为了响应 shebang 行指定您希望使用的 shell:
#!/bin/bash
如果您另存为 UTF-8,则没有 BOM(例如在 BBEdit 中)一切都会很好。
评论
仅当文件实际包含一些非 ASCII 字符时,带有 BOM 的 UTF-8 才有帮助。如果它被包含并且没有任何,那么它可能会破坏旧的应用程序,否则这些应用程序会将文件解释为纯 ASCII。当这些应用程序遇到非 ASCII 字符时,它们肯定会失败,因此在我看来,只有当文件可以并且不应该再被解释为纯 ASCII 时,才应该添加 BOM。
我想明确表示,我宁愿根本没有 BOM。如果一些旧的垃圾没有它,就会添加它,并且替换该旧应用程序是不可行的。
不要期望 UTF-8 的 BOM。
评论
wc(1)
问题:没有 BOM 的 UTF-8 和 UTF-8 有什么区别?哪个更好?
以下是维基百科上关于字节顺序标记 (BOM) 的文章的一些摘录,我相信它们为这个问题提供了可靠的答案。
关于 BOM 和 UTF-8 的含义:
Unicode 标准允许 UTF-8 格式的 BOM,但不要求 或推荐使用它。字节顺序在 UTF-8 中没有意义,因此其 在 UTF-8 中的唯一用途是在开始时发出文本流是 以 UTF-8 编码。
不使用 BOM 的参数:
不使用 BOM 的主要动机是向后兼容性 使用无法识别 Unicode 的软件...不的另一个动机 使用 BOM 是为了鼓励使用 UTF-8 作为“默认”编码。
使用 BOM 的参数:
使用 BOM 的论点是,没有它,启发式分析是 需要确定文件使用的字符编码。 从历史上看,为了区分各种 8 位编码,这种分析是 复杂,容易出错,有时速度慢。多个库 可用于简化任务,例如 Mozilla Universal Charset Unicode 的检测器和国际组件。
程序员错误地认为 UTF-8 的检测是平等的 困难(这不是因为绝大多数字节序列 是无效的 UTF-8,而这些库正在尝试的编码 区分允许所有可能的字节序列)。因此不是全部 Unicode 感知程序执行此类分析,而是依赖于 BOM。
特别是 Microsoft 编译器和解释器,以及许多 Microsoft Windows上的软件(如记事本)不会 正确读取 UTF-8 文本,除非它只有 ASCII 字符或 从 BOM 开始,并在保存文本时将 BOM 添加到开头 作为 UTF-8。当 Microsoft Word 文档 下载为纯文本文件。
在哪个更好,有或没有 BOM:
IETF 建议,如果协议 (a) 始终使用 UTF-8, 或 (b) 有其他方式来指示正在使用的编码, 然后它“应该禁止使用 U+FEFF 作为签名”。
我的结论:
仅当与软件应用程序的兼容性绝对必要时,才使用 BOM。
另请注意,虽然引用的维基百科文章指出,许多 Microsoft 应用程序依赖于 BOM 来正确检测 UTF-8,但并非所有 Microsoft 应用程序都是如此。例如,正如 @barlop 所指出的,当使用带有 UTF-8† 的 Windows 命令提示符时,命令不会出现 BOM。如果存在 BOM,则可能会像其他应用程序一样出现问题。type
more
† chcp
命令通过代码页 65001 提供对 UTF-8(不带 BOM)的支持。
评论
.htaccess
gzip compression
应该注意的是,对于某些文件,即使在 Windows 上也不得拥有 BOM。例如,或文件。如果此类文件包含 BOM,则在尝试执行它们时会出现错误。SQL*plus
VBScript
这个问题已经有一百零一个答案,其中许多都非常好,但我想尝试澄清何时应该或不应该使用 BOM。
如前所述,在确定字符串是否为 UTF-8 时,任何使用 UTF BOM(字节顺序标记)都是有根据的猜测。如果有适当的元数据可用(例如),那么您已经知道应该使用什么,但除此之外,您需要测试并做出一些假设。这涉及检查字符串来自的文件是否以十六进制字节码 EF BB BF 开头。charset="utf-8"
如果找到与 UTF-8 BOM 对应的字节码,则概率足够高,可以假设它是 UTF-8,您可以从那里开始。然而,当被迫做出这种猜测时,在阅读时进行额外的错误检查仍然是一个好主意,以防出现乱码。如果输入绝对不应该是 UTF-8(基于其源),则仅应假设 BOM 不是 UTF-8(即 latin-1 或 ANSI)。但是,如果没有 BOM,则可以通过针对编码进行验证来简单地确定它是否应该是 UTF-8。
为什么不推荐使用 BOM?
- 非 Unicode 感知或合规性差的软件可能会假定它是 latin-1 或 ANSI,并且不会从字符串中剥离 BOM,这显然会导致问题。
- 这并不是真正需要的(只需检查内容是否合规,并在找不到合规编码时始终使用 UTF-8 作为回退)
何时应使用 BOM 进行编码?
如果您无法以任何其他方式(通过字符集标记或文件系统元)记录元数据,并且像 BOM 一样使用的程序,则应使用 BOM 进行编码。在 Windows 上尤其如此,因为没有 BOM 的任何内容通常都假定使用旧代码页。BOM 告诉 Office 等程序,是的,此文件中的文本是 Unicode;下面是使用的编码。
归根结底,我唯一真正有问题的文件是 CSV。根据程序的不同,它必须或不得具有 BOM。例如,如果您在 Windows 上使用 Excel 2007+,则必须使用 BOM 对其进行编码,以便顺利打开它而不必求助于导入数据。
评论
以下是实际导致实际问题的 BOM 使用示例,但许多人对此一无所知。
BOM 中断脚本
Shell脚本,Perl脚本,Python脚本,Ruby脚本,Node.js脚本或任何其他需要由解释器运行的可执行文件 - 都以shebang行开头,看起来像其中之一:
#!/bin/sh
#!/usr/bin/python
#!/usr/local/bin/perl
#!/usr/bin/env node
它告诉系统在调用此类脚本时需要运行哪个解释器。如果脚本是用 UTF-8 编码的,人们可能会想在开头包含一个 BOM。但实际上,“#!”字符不仅仅是字符。它们实际上是一个神奇的数字,恰好由两个 ASCII 字符组成。如果在这些字符之前放置某些内容(如 BOM),则文件将看起来像具有不同的幻数,这可能会导致问题。
参见维基百科,文章:Shebang,部分:魔术数字:
shebang 字符由相同的两个字节表示 扩展的 ASCII 编码,包括 UTF-8,通常用于 当前类 Unix 系统上的脚本和其他文本文件。然而 UTF-8 文件可以以可选的字节顺序标记 (BOM) 开头;如果 “exec” 函数专门检测字节 0x23 和 0x21,然后 在 shebang 之前存在 BOM (0xEF 0xBB 0xBF) 将阻止 脚本解释器被执行。一些权威机构建议 反对在POSIX(类Unix)脚本中使用字节顺序标记,[14] 出于这个原因,以及更广泛的互操作性和哲学 关注。此外,在 UTF-8 中不需要字节顺序标记, 因为该编码没有字节序问题;它只用于 将编码标识为 UTF-8。[强调后加]
BOM 在 JSON 中是非法的
请参阅 RFC 7159 第 8.1 节:
实现不得在 JSON 文本的开头添加字节顺序标记。
BOM 在 JSON 中是冗余的
它不仅在 JSON 中是非法的,而且不需要确定字符编码,因为有更可靠的方法可以明确确定任何 JSON 流中使用的字符编码和字节序(有关详细信息,请参阅此答案)。
BOM 中断 JSON 解析器
它不仅在 JSON 中是非法的并且不需要,而且它实际上破坏了使用 RFC 4627 中提供的方法确定编码的所有软件:
确定 JSON 的编码和字节序,检查 NUL 字节的前四个字节:
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 不以三个 NUL 开头,因此不会被识别
- UTF-32LE 第一个字节后面没有三个 NUL,因此不会被识别
- UTF-16BE 在前四个字节中只有一个 NULL,因此无法识别
- UTF-16LE 在前四个字节中只有一个 NULL,因此无法识别
根据实现的不同,所有这些内容都可能被错误地解释为 UTF-8,然后被误解或拒绝为无效的 UTF-8,或者根本无法识别。
此外,如果实现测试了我建议的有效 JSON,它甚至会拒绝确实编码为 UTF-8 的输入,因为它不会像 RFC 那样以 ASCII 字符< 128 开头。
其他数据格式
不需要 JSON 中的 BOM,这是非法的,并且会破坏根据 RFC 正常工作的软件。当时不使用它应该是不费吹灰之力的,但是,总有人坚持使用 BOM、注释、不同的引用规则或不同的数据类型来破坏 JSON。当然,如果你需要的话,任何人都可以自由地使用BOM或其他任何东西--只是不要称它为JSON。
对于 JSON 以外的其他数据格式,请查看它的实际外观。如果唯一的编码是 UTF-*,并且第一个字符必须是低于 128 的 ASCII 字符,则您已经拥有确定数据的编码和字节序所需的所有信息。添加 BOM 表,即使作为可选功能,也只会使其更加复杂和容易出错。
BOM的其他用途
至于JSON或脚本之外的用途,我认为这里已经有非常好的答案了。我想添加有关脚本和序列化的更详细信息,因为它是 BOM 字符导致实际问题的示例。
评论
Unicode 字节顺序标记 (BOM) 常见问题解答提供了简明的答案:
问:我应该如何处理 BOM?
答:以下是一些需要遵循的准则:
特定协议(例如 Microsoft 对 .txt 文件的约定)可能需要在某些 Unicode 数据流上使用 BOM,例如 文件。当您需要遵守此类协议时,请使用 BOM。
某些协议允许在未标记文本的情况下使用可选的 BOM。在这些情况下,
如果已知文本数据流是纯文本,但编码未知,则 BOM 可以用作签名。如果没有 BOM, 编码可以是任何东西。
如果已知文本数据流是纯 Unicode 文本(但不是哪个字节序),则 BOM 可以用作签名。如果有 没有 BOM,则文本应解释为 big-endian。
一些面向字节的协议要求文件开头有 ASCII 字符。如果 UTF-8 与这些协议一起使用,请使用 应避免将 BOM 作为编码表单签名。
如果数据流的精确类型是已知的(例如,Unicode big-endian 或 Unicode little-endian),则不应使用 BOM。在 特别是,每当数据流被声明为 UTF-16BE, 不得使用 UTF-16LE、UTF-32BE 或 UTF-32LE 物料清单。
以下是我在 Visual Studio、Sourcetree 和 Bitbucket 拉取请求方面的经验,这给我带来了一些问题:
因此,事实证明,在审查拉取请求时,带有签名的 BOM 将在每个文件上包含一个红点字符(这可能很烦人)。
如果你将鼠标悬停在它上面,它会显示一个像“ufeff”这样的字符,但事实证明 Sourcetree 不显示这些类型的字节标记,所以它很可能会出现在你的拉取请求中,这应该没问题,因为这就是 Visual Studio 2017 现在编码新文件的方式,所以也许 Bitbucket 应该忽略这一点或让它以另一种方式显示, 更多信息在这里:
我用utf-8保存了一个自动热键文件,汉字变成了strrang。
使用 utf-8 BOM,工作正常。
AutoHotkey 不会自动识别 UTF-8 文件,除非它以字节顺序标记开头。
评论