928

UTF-8 和没有BOM的 UTF-8 有什么不同?哪个更好?

4

21 回答 21

870

UTF-8 BOM 是文本流 ( ) 开头的字节0xEF, 0xBB, 0xBF序列,它允许读者更可靠地猜测文件是用 UTF-8 编码的。

通常,BOM用于表示编码的字节顺序,但由于字节顺序与 UTF-8 无关,因此不需要 BOM。

根据Unicode 标准不推荐使用 UTF-8 文件的 BOM

2.6 编码方案

... UTF-8 既不需要也不建议使用 BOM,但在 UTF-8 数据从使用 BOM 的其他编码形式转换或 BOM 用作 UTF-8 签名的情况下可能会遇到. 有关详细信息,请参阅第 16.8 节,特价中的“字节顺序标记”小节。

于 2010-02-08T18:33:26.937 回答
267

其他出色的答案已经回答了:

  • UTF-8 和 BOM-ed UTF-8 之间没有官方区别
  • 一个 BOM-ed UTF-8 字符串将从以下三个字节开始。EF BB BF
  • 从文件/流中提取字符串时,必须忽略这些字节(如果存在)。

但是,作为对此的附加信息,如果字符串以 UTF-8 编码,则 UTF-8 的 BOM 可能是“闻”的好方法......或者它可能是任何其他编码的合法字符串......

例如,数据 [EF BB BF 41 42 43] 可以是:

  • 合法的ISO-8859-1字符串“ABC”
  • 合法的UTF-8字符串“ABC”

因此,虽然通过查看第一个字节来识别文件内容的编码可能很酷,但您不应该依赖它,如上面的示例所示

编码应该是已知的,而不是预测的。

于 2010-02-08T18:42:23.177 回答
145

将 BOM 放入 UTF-8 编码文件中至少存在三个问题。

  1. 不包含文本的文件不再为空,因为它们始终包含 BOM。
  2. 包含 UTF-8 的 ASCII 子集内的文本的文件本身不再是 ASCII,因为 BOM 不是 ASCII,这使得一些现有工具出现故障,并且用户不可能替换这些旧工具。
  3. 无法将多个文件连接在一起,因为现在每个文件的开头都有一个 BOM。

而且,正如其他人所提到的,拥有 BOM 来检测某些东西是 UTF-8 既不够也没有必要:

  • 这还不够,因为任意字节序列可能恰好以构成 BOM 的确切序列开始。
  • 这不是必需的,因为您可以像读取 UTF-8 一样读取字节;如果成功,则根据定义,它是有效的 UTF-8。
于 2012-11-15T13:28:57.627 回答
109

以下是实际导致实际问题但许多人不知道的 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

注意:

  1. UTF-32BE 不以三个 NUL 开头,所以不会被识别
  2. UTF-32LE 第一个字节后面没有三个NUL,所以不会被识别
  3. UTF-16BE 前四个字节只有一个 NUL,所以不会被识别
  4. UTF-16LE 前四个字节只有一个 NUL,所以不会被识别

根据实现的不同,所有这些都可能被错误地解释为 UTF-8,然后被误解为无效的 UTF-8 或被拒绝,或者根本无法识别。

此外,如果实现按照我的建议测试有效的 JSON,它甚至会拒绝确实编码为 UTF-8 的输入,因为它不是按照 RFC 应以 < 128 的 ASCII 字符开头。

其他数据格式

JSON 中的 BOM 不是必需的,是非法的,并且会破坏根据 RFC 正常工作的软件。那时不使用它应该是明智的,然而,总是有人坚持使用 BOM、注释、不同的引用规则或不同的数据类型来破坏 JSON。当然,如果您需要,任何人都可以自由使用诸如 BOM 之类的东西或其他任何东西——只是不要称它为 JSON。

对于 JSON 以外的其他数据格式,看看它的真实样子。如果唯一的编码是 UTF-* 并且第一个字符必须是小于 128 的 ASCII 字符,那么您已经拥有确定数据的编码和字节顺序所需的所有信息。即使将 BOM 作为可选功能添加也只会使其更加复杂和容易出错。

BOM 的其他用途

至于 JSON 或脚本之外的用途,我想这里已经有了很好的答案。我想添加更多关于脚本和序列化的详细信息,因为它是 BOM 字符导致实际问题的一个示例。

于 2016-06-26T11:34:10.720 回答
52

UTF-8 和没有 BOM 的 UTF-8 有什么不同?

简短回答:在 UTF-8 中,BOM 被编码为EF BB BF文件开头的字节。

长答案:

最初,人们期望Unicode以 UTF-16/UCS-2 编码。BOM 专为这种编码形式而设计。当您有 2 字节代码单元时,有必要指出这两个字节的顺序,并且这样做的常见约定是在数据开头包含字符 U+FEFF 作为“字节顺序标记”。字符 U+FFFE 是永久未分配的,因此它的存在可用于检测错误的字节顺序。

无论平台字节序如何,UTF-8 都具有相同的字节顺序,因此不需要字节顺序标记。但是,它可能(作为字节序列EF BB FF)出现在从 UTF-16 转换为 UTF-8 的数据中,或者作为“签名”来指示数据是 UTF-8。

哪个更好?

没有。正如 Martin Cote 所回答的,Unicode 标准不推荐它。它会导致非 BOM 感知软件出现问题。

检测文件是否为 UTF-8 的更好方法是执行有效性检查。UTF-8 对哪些字节序列有效有严格的规定,因此误报的可能性可以忽略不计。如果一个字节序列看起来像 UTF-8,它可能是。

于 2010-07-31T22:53:25.837 回答
35

带有 BOM 的 UTF-8 可以更好地识别。我很难得出这个结论。我正在开发一个项目,其中一个结果是CSV文件,包括 Unicode 字符。

如果 CSV 文件在没有 BOM 的情况下保存,Excel 会认为它是 ANSI 并显示乱码。在前面添加“EF BB BF”后(例如,通过使用带有 UTF-8 的记事本重新保存它;或使用带有 BOM 的 UTF-8 的 Notepad++ 重新保存它),Excel 可以正常打开它。

RFC 3629 建议将 BOM 字符添加到 Unicode 文本文件:“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 )

于 2012-06-28T17:34:28.737 回答
17

BOM 往往会在某处某处繁荣(没有双关语(原文如此))。并且当它繁荣时(例如,浏览器、编辑器等无法识别),它会在文档开头显示为奇怪的字符(例如,HTML 文件、JSON响应、RSS等)并造成类似最近在 Twitter 上谈论奥巴马时遇到的编码问题那样的尴尬。

当它出现在难以调试的地方或忽略测试时,这是非常烦人的。所以最好避免它,除非你必须使用它。

于 2011-07-11T07:56:16.883 回答
17

问题: UTF-8 和没有 BOM 的 UTF-8 有什么不同?哪个更好?

以下是关于字节顺序标记 (BOM)的 Wikipedia 文章的一些摘录,我相信这些文章为这个问题提供了可靠的答案。

关于 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 Detector 和 International Components for Unicode。

程序员错误地认为 UTF-8 的检测同样困难(这并不是因为绝大多数字节序列都是无效的 UTF-8,而这些库试图区分的编码允许所有可能的字节序列)。因此,并非所有支持 Unicode 的程序都执行此类分析,而是依赖 BOM。

特别是Microsoft编译器和解释器,以及 Microsoft Windows 上的许多软件(例如记事本)将无法正确读取 UTF-8 文本,除非它只有 ASCII 字符或以 BOM 开头,并且在保存时会在开头添加 BOM文本为 UTF-8。当 Microsoft Word 文档作为纯文本文件下载时,Google Docs 将添加 BOM。

哪个更好, 没有 BOM:

IETF建议,如果一个协议 (a) 始终使用 UTF-8,或者 (b) 有其他方式来指示正在使用什么编码,那么它“应该禁止使用 U+FEFF 作为签名”。</ p>

我的结论:

仅当与软件应用程序的兼容性绝对必要时才使用 BOM 。

另请注意,虽然引用的 Wikipedia 文章表明许多 Microsoft 应用程序依赖 BOM 来正确检测 UTF-8,但并非所有Microsoft 应用程序都是如此。例如,正如@barlop所指出的,当使用带有 UTF-8 type的 Windows 命令提示符时,这样的命令more并不期望 BOM 存在。如果存在 BOM ,可能会出现问题,因为它对于其他应用程序也是如此。


† 该命令通过代码页65001chcp提供对 UTF-8(没有BOM)的支持。

于 2014-10-02T20:24:24.993 回答
12

这个问题已经有一百万个答案,其中许多都很好,但我想尝试澄清何时应该或不应该使用 BOM。

如前所述,在确定字符串是否为 UTF-8 时使用 UTF BOM(字节顺序标记)都是有根据的猜测。如果有适当的元数据可用(如charset="utf-8"),那么您已经知道应该使用什么,但否则您需要测试并做出一些假设。这包括检查来自字符串的文件是否以十六进制字节码 EF BB BF 开头。

如果找到对应于 UTF-8 BOM 的字节码,则概率足够高,可以假设它是 UTF-8,您可以从那里开始。然而,当被迫做出这种猜测时,在阅读时进行额外的错误检查仍然是一个好主意,以防出现乱码。如果输入基于其源绝对不应该是UTF-8,则您应该只假设 BOM 不是 UTF-8(即 latin-1 或 ANSI) 。但是,如果没有 BOM,您可以通过验证编码来简单地确定它是否应该是 UTF-8。

为什么不推荐使用 BOM?

  1. 不支持 Unicode 或兼容性不佳的软件可能会假定它是 latin-1 或 ANSI,并且不会从字符串中剥离 BOM,这显然会导致问题。
  2. 它不是真的需要(只需检查内容是否兼容,并在找不到兼容编码时始终使用 UTF-8 作为后备)

什么时候应该使用 BOM 进行编码?

如果您无法以任何其他方式(通过字符集标记或文件系统元数据)记录元数据,并且使用的程序类似于 BOM,则应使用 BOM 进行编码。在 Windows 上尤其如此,通常假定没有 BOM 的任何内容都使用旧代码页。BOM 告诉像 Office 这样的程序,是的,这个文件中的文本是 Unicode;这是使用的编码。

归根结底,我真正遇到问题的唯一文件是 CSV。根据程序,它必须或不能有 BOM。例如,如果您在 Windows 上使用 Excel 2007+,如果您想顺利打开它并且不必求助于导入数据,则必须使用 BOM 对其进行编码。

于 2016-01-25T16:03:13.450 回答
8

不带 BOM 的 UTF-8 没有 BOM,这并不比带 BOM 的 UTF-8 更好,除非文件的使用者需要知道(或会受益于知道)文件是否是 UTF-8 编码的或不。

BOM 通常可用于确定编码的字节顺序,这对于大多数用例来说不是必需的。

此外,对于那些不了解或不关心 BOM 的消费者来说,BOM 可能是不必要的噪音/痛苦,并可能导致用户混淆。

于 2010-02-08T18:30:19.800 回答
8

应该注意的是,对于某些文件,即使在 Windows 上也不能有 BOM。示例是SQL*plusVBScript文件。如果此类文件包含 BOM,则在尝试执行它们时会出现错误。

于 2015-01-31T21:09:28.870 回答
7

在 BOM 的维基百科页面底部引用:http ://en.wikipedia.org/wiki/Byte-order_mark#cite_note-2

“对于 UTF-8 既不需要也不建议使用 BOM,但在 UTF-8 数据从使用 BOM 的其他编码形式转换或 BOM 用作 UTF-8 签名的情况下可能会遇到”

于 2010-02-08T18:35:41.307 回答
7

仅当文件实际上包含一些非 ASCII 字符时,带有 BOM 的 UTF-8 才有帮助。如果它被包含并且没有,那么它可能会破坏旧的应用程序,否则这些应用程序会将文件解释为纯 ASCII。这些应用程序在遇到非 ASCII 字符时肯定会失败,所以在我看来,只有在文件可以而且应该不再被解释为纯 ASCII 时才应该添加 BOM。

我想明确表示我更喜欢根本没有 BOM。如果一些旧的垃圾在没有它的情况下会损坏,请添加它,并且替换该遗留应用程序是不可行的。

不要期望 UTF-8 的 BOM。

于 2014-07-03T02:43:19.633 回答
6

我从不同的角度看待这个问题。我认为带有 BOM 的 UTF-8 更好,因为它提供了有关文件的更多信息。仅当我遇到问题时,我才使用没有 BOM 的 UTF-8。

我在我的页面上使用多种语言(甚至Cyrillic)很长时间了,当文件在没有 BOM 的情况下保存并且我重新打开它们以使用编辑器进行编辑时(正如cherouvim还指出的那样),某些字符已损坏。

请注意,当您尝试使用 UTF-8 编码保存新创建的文件时,Windows 的经典记事本会自动使用 BOM 保存文件。

我个人用 BOM 保存服务器端脚本文件(.asp、.ini、.aspx)和不带 BOM.html 文件

于 2012-05-11T08:34:50.557 回答
6

当您想显示以 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 文件中。

于 2012-09-10T16:50:05.727 回答
6

一个实际的区别是,如果您为 Mac OS X 编写一个 shell 脚本并将其保存为纯 UTF-8,您将得到响应:

#!/bin/bash: No such file or directory

响应 shebang 行,指定您希望使用的外壳:

#!/bin/bash

如果您保存为 UTF-8,则没有 BOM(例如在BBEdit中)一切都会好起来的。

于 2014-01-24T20:38:21.520 回答
5

Unicode字节顺序标记 (BOM) 常见问题解答提供了简洁的答案:

问:我应该如何处理 BOM?

答:以下是一些需要遵循的准则:

  1. 特定协议(例如 Microsoft 对 .txt 文件的约定)可能需要在某些 Unicode 数据流(例如文件)上使用 BOM。当您需要遵守此类协议时,请使用 BOM。

  2. 某些协议允许在未标记文本的情况下使用可选的 BOM。在那些情况下,

    • 在已知文本数据流是纯文本但编码未知的情况下,BOM 可用作签名。如果没有 BOM,则编码可以是任何东西。

    • 如果已知文本数据流是纯 Unicode 文本(但不是哪个字节序),则 BOM 可用作签名。如果没有 BOM,则应将文本解释为大端。

  3. 一些面向字节的协议要求在文件开头使用 ASCII 字符。如果 UTF-8 与这些协议一起使用,则应避免使用 BOM 作为编码形式签名。

  4. 如果数据流的精确类型已知(例如 Unicode big-endian 或 Unicode little-endian),则不应使用 BOM。特别是,当数据流被声明为 UTF-16BE、UTF-16LE、UTF-32BE 或 UTF-32LE 时,不得使用 BOM。

于 2018-03-08T13:58:08.147 回答
4

如上所述,带有 BOM 的 UTF-8 可能会导致非 BOM 感知(或兼容)软件出现问题。我曾经使用基于 Mozilla 的KompoZer编辑编码为 UTF-8 + BOM 的 HTML 文件,因为客户端需要WYSIWYG程序。

保存时布局总是会被破坏。我花了一些时间来解决这个问题。这些文件随后在 Firefox 中运行良好,但在 Internet Explorer 中显示了一个 CSS 怪癖,再次破坏了布局。在摆弄链接的 CSS 文件数小时无济于事后,我发现 Internet Explorer 不喜欢 BOMfed HTML 文件。再也不。

另外,我刚刚在维基百科中找到了这个:

shebang 字符由扩展 ASCII 编码中的相同两个字节表示,包括 UTF-8,它通常用于当前类 Unix 系统上的脚本和其他文本文件。但是,UTF-8 文件可能以可选的字节顺序标记 (BOM) 开头;如果“exec”函数专门检测到字节 0x23 0x21,那么在 shebang 之前存在 BOM(0xEF 0xBB 0xBF)将阻止脚本解释器被执行。一些权威机构建议不要在 POSIX(类 Unix)脚本中使用字节顺序标记,[15] 出于这个原因以及更广泛的互操作性和哲学问题

于 2013-06-22T04:56:19.603 回答
3

来自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,这会导致后续开发链中的其他问题。

于 2010-02-08T18:31:00.657 回答
1

这是我在 Visual Studio、Sourcetree和 Bitbucket 拉取请求方面的经验,这给我带来了一些问题:

因此,在审查拉取请求时,带有签名的 BOM 将在每个文件上包含一个红点字符(这可能很烦人)。

在此处输入图像描述

如果你将鼠标悬停在它上面,它会显示一个像“ufeff”这样的字符,但事实证明 Sourcetree 没有显示这些类型的字节标记,所以它很可能会出现在你的拉取请求中,这应该没问题,因为这就是 Visual Studio 2017 现在编码新文件,所以也许 Bitbucket 应该忽略这一点或让它以另一种方式显示,更多信息在这里:

红点标记 BitBucket 差异视图

于 2019-07-31T09:30:27.433 回答
-4

如果您在 HTML 文件中使用 UTF-8 并且如果您在同一页面上使用塞尔维亚西里尔文、塞尔维亚拉丁文、德文、匈牙利文或一些异国语言,则带有 BOM 的 UTF 会更好。

这是我的观点(30 年的计算和 IT 行业)。

于 2013-03-15T10:01:53.000 回答