UTF8文件带BOM引起的问题

起因是公司iOS端竟然加载除了HTML代码,百思不得其解,查文献,原来如此...

UTF-8 不需要 BOM,尽管 Unicode 标准允许在 UTF-8 中使用 BOM。
所以不含 BOM 的 UTF-8 才是标准形式,在 UTF-8 文件中放置 BOM 主要是微软的习惯(顺便提一下:把带有 BOM 的小端序 UTF-16 称作「Unicode」而又不详细说明,这也是微软的习惯)。
BOM(byte order mark)是为 UTF-16 和 UTF-32 准备的,用于标记字节序(byte order)微软在 UTF-8 中使用 BOM 是因为这样可以把 UTF-8 和 ASCII 等编码明确区分开,但这样的文件在 Windows 之外的操作系统里会带来问题。

「UTF-8」和「带 BOM 的 UTF-8」的区别就是有没有 BOM。即文件开头有没有 U+FEFF。
UTF-8 的网页代码不应使用 BOM,否则常常会出错。这是一个小例子: 为什么这个网页代码 <head> 内的信息会被浏览器理解为在 <body> 内?

另附《The Unicode Standard, Version 6.0》之 3.10 D95 UTF-8 encoding scheme 的一段话:
While there is obviously no need for a byte order signature when using UTF-8, there are occasions when processes convert UTF-16 or UTF-32 data containing a byte order mark into UTF-8. When represented in UTF-8, the byte order mark turns into the byte sequence. Its usage at the beginning of a UTF-8 data stream is neither required nor recommended by the Unicode Standard, but its presence does not affect conformance to the UTF-8 encoding scheme. Identification of the byte sequence at the beginning of a data stream can, however, be taken as a near-certain indication that the data stream is using the UTF-8 encoding scheme.
http://www.unicode.org/versions/Unicode6.0.0/ch03.pdf

---------------------------------------------------------
首先,BOM是啥。这个就不解释了,Wikipedia上很详细。http://en.wikipedia.org/wiki/Byte_order_mark。
在网页上使用BOM是个错误。BOM设计出来不是用来支持HTML和XML的。要识别文本编码,HTML有charset属性,XML有encoding属性,没必要拉BOM撑场面。虽然理论上BOM可以用来识别UTF-16编码的HTML页面,但实际工程上很少有人这么干。毕竟UTF-16这种编码连ASCII都双字节,实在不适用于做网页。

其实说BOM是个坏习惯也不尽然。BOM也是Unicode标准的一部分,有它特定的适用范围。通常BOM是用来标示Unicode纯文本字节流的,用来提供一种方便的方法让文本处理程序识别读入的.txt文件是哪个Unicode编码(UTF-8,UTF-16BE,UTF-16LE)。Windows相对对BOM处理比较好,是因为Windows把Unicode识别代码集成进了API里,主要是CreateFile()。打开文本文件时它会自动识别并剔除BOM。Windows用这个有历史原因,因为它最初脱胎于多代码页的环境(ANSI环境)。而引入Unicode时Windows的设计者又希望能在用户不注意的情况下同时兼容Unicode和非Unicode(Multiple byte)文本文件,就只能借助这种小trick了。相比之下,Linux这样的系统在多locale的环境中浸染的时间比较短,再加上社区本身也有足够的动力轻装前进(吐槽:微软对兼容性的要求确实是到了非常偏执的地步,任何一点破坏兼容性的做法都不允许,以至于很多时候是自己绑住自己的双手),所以干脆一步到位进入UTF-8。当然中间其实有一段过渡期,比如从最初全UTF-8的GTK+2.0发布到基本上所有GTK开发者都弃用多locale的GTK+1.2,我印象中至少经历了三到四年。

BOM不受欢迎主要是在UNIX环境下,因为很多UNIX程序不鸟BOM。主要问题出在UNIX那个所有脚本语言通行的首行#!标示,这东西依赖于shell解析,而很多shell出于兼容的考虑不检测BOM,所以加进BOM时shell会把它解释为某个普通字符输入导致破坏#!标示,这就麻烦了。其实很多现代脚本语言,比如Python,其解释器本身都是能处理BOM的,但是shell卡在这里,没办法,只能躺着也中枪。说起来这也不能怪shell,因为BOM本身违反了一个UNIX设计的常见原则,就是文档中存在的数据必须可见。BOM不能作为可见字符被文本编辑器编辑,就这一条很多UNIX开发者就不满意。

顺便说一句,即使脚本语言能处理BOM,随处使用BOM也不是推荐的办法。各个脚本语言对Unicode的处理都有自己的一套,Python的 # -*- coding: utf-8 -*-,Perl的use utf8,都比BOM简单而且可靠。另一个好消息是,即使是必须在Windows和UNIX之间切换的朋友也不会悲催。幸亏在UNIX环境下我们还有VIM这种神器,即使遇到BOM挡道,我们也可以通过 set nobomb; set fileencoding=utf8; w 三条命令解决问题。

最后回头想想,似乎也真就只有Windows坚持用BOM了。

P.S.:本问题是自己的第150个回答。突然发现自己回答得很少很少??
P.S. 2:突然想起需要解释一下为什么说VIM去除bomb的操作需要在UNIX下完成。因为VIM在Windows环境下有一个奇怪的bug,总是把UTF-16文件识别成二进制文件,而UNIX(Linux或者Mac都可以)下VIM则无问题。这个问题从VIM 6.8一直跟着我到VIM 7.3。目前尚不清楚这是VIM的bug还是我自己那个.vimrc文件的bug。如有高手解答不胜感激。

---------------------------------------------------------

有bom格式在开头会多出3个字节 EF BB BF ,主要用于识别编码。bom应该是windows特有的,在制作网页时会产生各种意想不到的问题,例如多输出了一个空行,影响PHP的session或者cookies功能(出现 header already sent错误),甚至可能引起页面的乱码(那3个字节影响了浏览器对页面编码的处理),因此总是推荐使用无bom编码。为了处理这个问题我甚至写了一个批量处理的PHP脚本。

---------------------------------------------------------
邸强,软件开发ing
张旭东、Mingyue Zhou、sapjax 赞同
几周前还在为BOM的问题苦恼着。。。
正如@梁海所说,“不含 BOM 的 UTF-8 才是标准形式”,的确是这样,无BOM使用得更多些,所以个人还是推荐一般情况下用无BOM的形式吧,除非有问题的时候,再考虑换有BOM的。Windows系统保存的都是有BOM的,所以你可以看到,用记事本保存一个UTF-8的txt,其实是有BOM的,这一点需要注意。另外不同的文本编辑器对于有无BOM的称呼也略有不同,比如EditPlus,有BOM的称为UTF-8+,无BOM的称为UTF-8,而在Notepad++中,有BOM的被称为标准UTF-8,而无BOM则被称为UTF-8无BOM。

---------------------------------------------------------
武龙飞,c/c++ 程序员,喜欢天文学,数学和心理学。
Weijing Huang、Bill Chan、icky R 赞同
以下文字出自我的博客内容,从另一面解说不一样的bom。
---------------------------------------------------------
字符编码相信是每个程序员的噩梦,只要是有中文的地方,总是会遇到各种编码的问题,并且这种问题还非常难缠,尤其在linux上,因为上面很多软件都是针对英语国家开发的,是不会考虑其他语种编码问题。在遇到编码的无数大坑之后,我决定仔细研究下编码问题,因为这就像一道坎一直横在你面前,每次到这里你都会跌到,每次爬起来之后,你都若无其事,这样的人被称作战士,真正的战士。可惜是个力量战士,做为新时代的智力战士,当然不能在那跌到然后又在这继续跌到。
文件的存储方式:
文件都有自己的存储格式,比如最常见的txt,cpp,h,c,xml ,png, rmvb各种格式,还有自定义格式。这些文件不论是什么格式,都是存储在计算机硬盘里的2进制格存储,对应不同文件格式,有不同的软件解析。这篇文章不谈文件是如何存储的,只谈文件是如何解析的。
文本文件解析:
文本文件对应于人类可以阅读的文本,如何从2进制转换为文本文件呢?起初由于计算机在美国发明,自然大家考虑的是英语如何表示,英语字母总共26个,加上特殊字符,128个字符,7位既一个byte即可表示出来。这个就是大家所熟知的ascill编码。对应关系很简单,一个字符对应一一个byte。
但很快发现,其他非英语国家的文字远远超过ascill码,这时候大家当然想统一一下,不同国家出了自己不同的编码方式,中国的gb2312就是自己做出来的编码方式,这样下去每个国家都有自己的编码方式,来回转换太麻烦了。这时候出现了新的编码方式,unicode编码方式,想将编码统一,所以规定了每个字符对应的unicode码。
1、很多文件都是ascii编码,如果用unicode 太浪费。
2、没有标志位说明该几个字节来解析为一个符号。
这时候拯救世界的utf出现了,utf是unicode的一种实现,只不过更聪明了。utf16是占用两字节,或者四字节,utf32是占用四字节。utf8是很聪明的一种表示方式。
1、对于单字节符号,字节第一位为0,后面7位表示字节编码。
2、对于n字节符号,第一字节的前n位都设为1,第n+1位为0,其余位位编码位置。
对于不同的编码,在文本的最前方有不同的标志,unicode 通常有两位来表示分别是ff fe, 或者feff, fffe表示big-endian 编码feff表示litte-endian编码。utf8是efbbbf来开头的。可以看出来utf-8是自解释的,所以不用带这个标志文件,大多数程序是可以识别的。但有些程序不能识别这个标志,比如php就会直接把这个标志当文本解析,不会忽略。相信很多遇到php输出文本解析乱码或者解析错误的同学都遇到这样的问题。
最后说说如何去掉或者加上bom,如果有vim那最好不过了,去掉命令:
set encoding=utf-8
set nobomb
添加命令:
set encoding=utf-8
set bomb
---------------------------------------------------------
带 BOM 的 UTF-8 就是赤裸裸的流氓!!!!!!!!!

windows总是自做聪明的做一些别人无法理解的事情!!!UTF-8是不需要BOM头的~~~!!

从刚开始学习代码(实在不能称我做的东西为程序)到现在,不晓得被这个BOM头搞了多少次,特别是对于我这种完全自学的人,知道找一个BUG需要多久多久不????

带不带BOM头区别就在于这个BOM头,祥见排名靠前的大神答案。windows特有的奇葩。请使用UTF-8 不带BOM头!!

它产生的BUG包含但不仅限于:
锘 -- 感谢 @飞扬 提供,参考其答案
HTML空白行
div之间莫明的间隔
乱码!
如果你用ssl那么一定会有问题!!!

顺便再鄙视一下 SONY的记忆棒、IPHONE的接口~~

这种吐槽的东西就让它折叠吧
--------------------------------------------------------
带 BOM 的 UTF-8 非常操蛋,经常造成莫名其妙的问题。
---------------------------------------------------------
我都是用的UTF-8 without BOM,带BOM的经常出现乱码
---------------------------------------------------------
notepad++会自动添加为带Bom的utf8比较坑爹
---------------------------------------------------------
建议编程人员能使用 Mac 编程的尽量使用Mac,Window是及其操蛋的操作系统。其次,如果我们要读取三方的文件并以UTF-8格式解析的时候一定要注意去判断这个文件是否有BOM,例如:sql文件的解析执行。
---------------------------------------------------------
网页编程中用不用bom我就不说什么了,因为软件原因无法使用的就更不能用了。

最近在学习用cocos2d-x,纯C++的编码,如果代码中有中文等的非ascii字符出现。发现会出错。代码是在mac 下用xcode 写的,放到windows 下用vs 编译。
最后把所有的源文件转成了带bom的格式后编译通过了,链接失败,这想这个就不是编码的问题了。

通常情况下,一般都 会认为在写C++代码的时候不要用中文,但是很多时候我们程序员也有想自己看着舒服的时候,为神马就不能写中文了?

于是在windows 下写了一个helloworld.cpp 类型的文件,输出内容用中文,然后存为utf-8 带bom格式,再把它copy到mac 下用g++ 编译,发现成功通过并且可正常运行,用xcode打开源文件也正常显示。

所以,这里建议程序要在windows 和 mac 还有linux 上运行的话,源代码最好保存成utf-8 带bom的格式,这样比较通用一些。而用utf-16 无论大端还是小端,g++ 都不认的。或者用utf-8 不带bom格式,然后代码不要出现非ascii 127以后的字符。

关于说utf-8 不带bom 才是标准的,我想应该是带用个人情绪的说法吧。真正的标准应该是bom是可选的,为什么可选?因为有些时候不带bom会出错,就拿历史较久远的windows来讲吧,很多国家的用户都在用windows ,其文件都是用其本地的ansi 编码来做的,比如大陆的GBK和GB2013,港台的big5,这些编码因为针对当地所用的字符制定的,所以呢,其存储文件较小,所以会大量使用,并且也大量存在着,微软不可能不考虑全球几十亿的用户的文件而盲目地修改解码方式,并且微软也是uncode 制定者之一,所以,带用bom的utf-8也是符合国际标准的。

或许是因为程序编写者的个人原因,也许是考虑到效率,很多的程序无法正确区分一个utf-8文件是否有bom,所以导致了各种乱码的出现。

个人不想说哪个是标准,也不想用语言去攻击哪个公司或团体。微软在坚持使用bom上没有错,因为这是在为用户考虑的。也许给我们这些写程序的带来了不便,但是,计算机最广泛的用户不是程序员。
---------------------------------------------------------
摘自:
http://www.zhihu.com/question/20167122

原文地址:https://www.cnblogs.com/yiyi17/p/10335839.html

时间: 2024-10-10 01:09:09

UTF8文件带BOM引起的问题的相关文章

生成不带BOM头的UTF-8文件

UTF-8(带BOM):writer = New StreamWriter(FilePathName, True, System.Text.UTF8Encoding.UTF8) UTF-8(不带BOM):writer =New StreamWriter(FilePathName, True, New UTF8Encoding(False)) 生成不带BOM头的UTF-8文件,布布扣,bubuko.com

UTF8带BOM和不带BOM(转载)

UTF-8 不需要 BOM,尽管 Unicode 标准允许在 UTF-8 中使用 BOM.所以不含 BOM 的 UTF-8 才是标准形式,在 UTF-8 文件中放置 BOM 主要是微软的习惯(顺便提一下:把带有 BOM 的小端序 UTF-16 称作「Unicode」而又不详细说明,这也是微软的习惯).BOM(byte order mark)是为 UTF-16 和 UTF-32 准备的,用于标记字节序(byte order).微软在 UTF-8 中使用 BOM 是因为这样可以把 UTF-8 和 A

php -- PHP5中file_get_contents函数获取带BOM的utf-8文件内容

最近,在用file_get_contents函数来取得文本的内容的时候,出现了一个情况(如下),苦思冥想了n久,不得其解,最后,果然还是得靠百度啊..... 百度到一个解释,下面是原文: PHP5中的file_get_contents函数获取文件内容,实际是按二进制来读取的,所以,当你用file_get_contents去获取一个带BOM的UTF-8文件时,它并不会把UTF-8的BOM去掉,当你把读取 的内容当作文本内容来进行一些操作时,可能会发生一些意想不到的结果.这并不能算作一个BUG,因为

UTF-8文件编码格式中有无签名问题汇总(BOM)

UTF-8签名(UTF-8 signature)也叫做BOM(Byte order Mark),是UTF编码方案里用于标识编码的标准标记.如果多个文件设置了签名,在二进制流中就会包含多个UTF-8签名,而IE是无法识别多个UTF-8签名的,所以用一个空行来代替,在某些程序处理中还会出现一个类似"诺"的字符. BOM(Byte Order Mark),是UTF编码方案里用于标识编码的标准标记,在UTF-16里本来是FF FE,变成UTF-8就成了EF BB BF(239 187 191)

【分享】Android Studio专用文件转换工具:把ANSI文件批量另存为无BOM的UTF-8文件

[分享]Android Studio专用文件转换工具:把ANSI文件批量另存为无BOM的UTF-8文件 在Andoird Studio下编译java文件时,经常会出现像下面的错误: Error:(29, 43) 閿欒: 缂栫爜UTF-8鐨勪笉鍙槧灏勫瓧绗? 在这里,分享一个工具:ANSI文件批量另存为无BOM的UTF-8文件: 把下面代码用记事本存为AndroidStudioJava编码.vbs,双击即可使用: on error resume next Set WshShell=WScrip

C#写UTF8文件时指定是否含BOM头

BOM的基本概念 在UCS 编码中有一个叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的编码是FEFF.而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中.UCS规范建议我们在传输字节流前,先传输字符"ZERO WIDTH NO-BREAK SPACE".这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的:如果收到FFFE,就表明这个字节流是Little-Endian的.因此字符"ZERO WIDTH N

Java读取UTF-8格式文件第一行出现乱码——问号“?”及解决 And Java读带有BOM的UTF-8文件乱码原因及解决方法

测试例子: Java读取UTF-8的txt文件第一行出现乱码"?"及解决 test.txt文件内容: 1 00:00:06,000 --> 00:00:06,010 <b>Allerleirauh</b> (2012) <i>dTV - Das Erste - 20. Januar 2013</i> 2 00:00:10,280 --> 00:00:12,680 Was geh?rt zu einer guten Suppe?

UTF-8文件的Unicode签名BOM(Byte Order Mark)问题记录(EF BB BF)

背景 楼主测试的批量发送信息功能上线之后,查看后台运行日志,发现存在少量的ERROR日志,提示手机号码格式不正确. 之前没有出现过这样的问题,找运营要了上传的txt发送列表,发现格式是要求的UTF-8,且号码是符合规则的,反复查看未发现异常. 因为博主还有别的需求,所以直接反馈给了开发,让开发定位. 定位过程 两天之后,开发给了我两个文件,问我有没有办法找出这两个文件的不同.我看了一下,文件内容完全相同. 后来使用软件beyond compare进行十六进制对比终于发现了区别, 其中一个第一行多

python 带BOM utf-8的响应解码

接口响应编码格式为带BOM头utf-8.直接获取响应的text出现乱码. '''dinghanhua2018-11requests text与content,指定响应的encoding''' api = 'http://testapi'response = requests.get(api) print(response.text)  乱码 解决方式: 1 获取content再用utf-8-sig decode. 2  指定响应的编码格式为utf-8-sig.再获取text. 1 指定respo