关于java生成UTF-8编码格式文件的诡异问题

原文地址

用java生成一个UTF-8文件(指定了utf-8格式了):

如果文件内容中没有中文内容,则生成的文件为ANSI编码格式;

如果文件内容中有中文内容,则生成的文件为UTF-8编码格式。

(用windows记事本查看的文本文件是什么格式)

也就是说,如果你的文件内容没有中文内容的话,你生成的文件是ANSI编码的。

http://stephen830.iteye.com/blog/259872

UTF8的优劣分析

http://zh.wikipedia.org/wiki/UTF-8

关于UTF8文件中的BOM头

在UCS 编码中有一个叫做“ZERO WIDTH NO-BREAK SPACE”的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中。UCS规范建议我们在传输字节流前,先传输字符“ZERO WIDTH NO-BREAK SPACE”。这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little- Endian的。因此字符“ZERO WIDTH NO-BREAK SPACE”又被称作BOM。BOM是“Byte Order Mark”的缩写。

UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。BOM的UTF-8编码是EF BB BF。所以如果接收者收到以EF BB BF开头的字节流,就知道这是UTF-8编码了。

几个常用的文本编辑器对BOM的处理办法是:

1) notepad : 可以自动识别出没有带 bom 的 utf-8 编码格式文件,但不可以控制保存文件时是否添加 bom , 如果保存文件,那么会统一添加 bom 。

2)editplus : 不能自动识别出没有 bom 的 utf-8 编码格式文件,文件保存时,选择UTF-8 格式,不会在文件头写上 BOM header.

3) UltraEdit : 对于字符编码的功能最为强大, 可以自动识别带 bom 和不带 bom 的 utf-8 文件 (可以配置) ; 保存的时候可以通过配置选择是否添加 bom.

(特别需要注意的是,保存一个新建立的文件时, 需要选择另存为 utf-8 no bom 格式)

另外一篇:

http://www.qinychun.com/2012/08/bom/231.html:UTF-8 的BOM对UFT-8没有作用。

FF FE是Unicode的Bom,Unicode当然是双字节,UTF-8的Bom是EF BB BF。

UTF-8 不需要 BOM,尽管 Unicode 标准允许在 UTF-8 中使用 BOM。

所以不含 BOM 的 UTF-8 才是标准形式,在 UTF-8 文件中放置 BOM 主要是微软的习惯(顺便提一下:把 UTF-16LE 称作「Unicode」而又不详细说明,这也是微软的习惯)。

(微软可气的是,如果不包含bom的utf-8,记事本还能正常显示;但是excel如果要显示utf-8的无bom csv文件,则直接乱码,,擦。。。)

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。。

http://www.jb51.net/article/9794.htm

UTF-8字节组合(二进制)

0xxxxxxx

110xxxxx 10xxxxxx

1110xxxx 10xxxxxx 10xxxxxx

11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

在UTF-8内,

1. 如果一个字节,最高位(第8位)为0,表示这是一个ASCII字符(00 - 7F)。可见,所有ASCII编码已经是UTF-8了。

2. 如果一个字节,以11开头,连续的1的个数暗示这个字符的字节数,例如:110xxxxx代表它是双字节UTF-8字符的首字节。

3. 如果一个字节,以10开始,表示它不是首字节,需要向前查找才能得到当前字符的首字节。

可见UTF-8可以有效地保证数据的完整性,避免出现编码的错位。即使偶然出现“坏字”,也不会影响到后续的文本。

对于在BMP中的中文字来说,需要用3个字节才能表示,比使用UTF-16或直接使用双字节的GB2312编码大了0.5倍。

Unicode签名bom详细说明

所谓的unicode保存的文件实际上是utf-16,只不过恰好跟unicode的码相同而已,但在概念上unicode与utf是两回事,unicode是内存编码表示方案,而utf是如何保存和传输unicode的方案。utf-16还分高位在前(LE)和高位在后(BE)两种(big endian和little endian称作“大尾”和“小尾”,http://blog.csdn.net/ustc_dylan/article/details/5859721)。官方的utf编码还有utf-32,也分LE和BE。非unicode官方的utf编码还有utf-7,主要用于邮件传输。utf-8的单字节部分是和iso-8859-1兼容的,这主要是一些旧的系统和库函数不能正确处理utf-16而被迫出来的,而且对英语字符来说,也节省保存的文件空间(以非英语字符浪费空间为代价)。在iso-8859-1的时候,utf8和iso-8859-1都是用一个字节表示的,当表示其它字符的时候,utf-8会使用两个或三个字节。

http://blog.csdn.net/huangjianxiang1875/article/details/8243302

后记:UTF-8以字节为编码单元,它的字节顺序在所有系统中都是一様的,没有字节序的问题,也因此它实际上并不需要BOM。

unicode有具体对应码表,比如\t0061(十六进制,对应'a';00高位,61低位),但是实际字节数组是用be,还是le表示都不太相同,比如java使用utf-16be,而有些语言使用utf-16le(微软把这个才叫unicode),可以通过bom推断高低位再组装数据。

java的unicode内存表示默认使用是UTF-16BE。

我这里写了一个例子,把字符串”我是好人”,以unicode编码写入到文本中,用InputStreamReader以”UTF-16LE”编码读取,输出的结果为:“???絙?”,而以“UTF-16BE”编码读取,结果则是“?我是好人”,文件大小显示为10字节。我的理解是,如果程序中指定使用unicode编码,但是没有指定字节顺序,程序会用java默认的UTF-16BE进行编码,并且,会输出标志位FEFF。所以文件中多了两个字节。而读取的时候,使用unicode编码读取,程序不知道使用的是哪一种字节顺序,先读取开头的FEFF,结果表明是采用的UTF-16BE编码,接下来再继续解析,就得到正确字符。而如果指定使用UTF-16LE编码,因为已经包含了字节顺序,所以就直接从字节数组中读取形成字符串,就出现了五个字符,而且由于编码格式不一样,除了‘好‘和‘絙’的编码刚好高低位倒置,还可以形成字符,其余全都是乱码。而使用UTF-16BE编码读取,因为已经制定了字节顺序,所以,也就不去读取标志位,那么就把unicode中无法编码的FEFF解码成为了‘?’。

比如字符0xabcd,它的存储格式到底是 AB CD,还是 CD AB 呢?

实际上两者都有可能,并分别有不同的名字。如果存储为 AB CD,则称为Big Endian; 如果存储为 CD AB,则称为Little Endian。值(0xabcd)的高位(0xab)。

http://tech.idv2.com/2008/02/21/unicode-intro/

Big Endian解释

最低位地址存放高位字节,可称高位优先,内存从最低地址开始按顺序存放(高数位数字先写)。最高位字节放最前面。例如“汉”字的Unicode编码是6C49。如果将6C写在前面,就是big endian。还是将49写在前面,就是little endian

Unicode规范中推荐的标记字节顺序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是Byte Order Mark。BOM是一个有点小聪明的想法:

在UCS编码中有一个叫做'ZERO WIDTH NO-BREAK SPACE'的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中。UCS规范建议我们在传输字节流前,先传输字符'ZERO WIDTH NO-BREAK SPACE'。

这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的。因此字符'ZERO WIDTH NO-BREAK SPACE'又被称作BOM。

其实big endian是指低地址存放最高有效字节(MSB),而little endian则是低地址存放最低有效字节(LSB)。

http://blog.csdn.net/sunshine1314/article/details/2309655

推荐阅读更多精彩内容