UTF-8 的BOM带来的麻烦

摘要:
UTF-8的BOM造成的问题需要我用程序生成一个html文件。易于使用的html文件被EmEditor认为是UTF-8withoutSignature。对于这两种UTF-8格式的转换,我检查了在线信息,并在记事本、EmEditor和其他文本编辑器中单击了“另存为”。选择UTF-8编码格式后,AddaUnicodeSignature将被激活。只要选中它,我的文件就可以保存为UTF-8withSignature格式。开始在谷歌上使用签名、BOM、AddaUnicodeSignature和其他关键字搜索UTF-8。Word=java%2Bom&url=http%3A//tgdem530%2Blogchina%2Economy/&b=0&a=1&user=baiduc,UTF和BOMUUTF-8的字节顺序以字节为编码单位,没有字节顺序的问题。在Unicode规范中标记字节顺序的推荐方法是BOM。

UTF-8 的BOM带来的麻烦


 

工作需要我用程序生成一个html文件。
由于服务器端使用apache+Tomcat来执行html和jsp文件。
开始生成html文件放在apache目录下,页面无法默认正常识别我页面设置的编码。

必须手动在浏览器上选择Encoding->简体中文(GB2312)才可以正常显示。
这样当然是不行了。
由于我们原来有一个页面是可以正常显示中文的,查看了一下,是UTF-8的格式,于是我也修改程序。
a.修改了页面的编码声明:

b.修改了写字节流的一个方法:
public void htmlWrite(String charsetName) {
        try {
            out = new BufferedWriter(new OutputStreamWriter(
                        new FileOutputStream(outFileName), "UTF-8"));
            out.write(res);
            out.flush();

            if (out != null) {
                out.close();
            }
        } catch (Exception e) {
            try {
                if (out != null) {
                    out.close();
                }
            } catch (IOException e1) {
                System.out.print("write errors!" + e);
            }

            System.out.print("write errors!" + e);
        }
    }
这样,我又生成了一个html,放在服务器下面,可问题又来了,还是无法正常显示,即浏览器无法默认识别为UTF-8的编码方式。奇怪,使用EmEditor打开,和好用的那个页面对比。没有任何问题。唯一的区别在于:
    我生成的那个html文件被EmEditor认为UTF-8 with Signature。而好用的那个html文件被EmEditor认为UTF-8 without Signature.
    对于这两种UTF-8格式的转换,我查看了网上信息,点击记事本,EmEditor等文本编辑器的另存为,当选择了UTF-8的编码格式时,Add a Unicode Signature(BOM)这个选项被激活,只要选择上,我的文件就可以存为UTF-8 with Signature的格式。可是,问题就在于,我用java怎么让我的文件直接生成为 UTF-8 with Signature的格式。
    开始上google搜索UTF-8 with Signature,BOM,Add a Unicode Signature等关键字。
http://www.unicode.org/unicode/faq/utf_bom.html#BOM
我大致了解了他们两个的区别。
Q: What is a BOM?

A: A byte order mark (BOM) consists of the character code U+FEFF at the beginning of a data stream, where it can be used as a signature defining the byte order and encoding form, primarily of unmarked plaintext files. Under some higher level protocols, use of a BOM may be mandatory (or prohibited) in the Unicode data stream defined in that protocol.
http://mindprod.com/jgloss/bom.html
BOM
Byte Order Marks are special characters at the beginning of a Unicode file to indicate whether it is big or little endian, in other words does the high or low order byte come first. These codes also tell whether the encoding is 8, 16 or 32 bit. You can recognise Unicode files by their starting byte order marks, and by the way Unicode-16 files are half zeroes and Unicode-32 files are three-quarters zeros. Unicode Endian Markers
Byte-order mark Description
EF BB BF UTF-8
FF FE UTF-16 aka UCS-2, little endian
FE FF UTF-16 aka UCS-2, big endian
00 00 FF FE UTF-32 aka UCS-4, little endian.
00 00 FE FF UTF-32 aka UCS-4, big-endian.
There are also variants of these encodings that have an implied endian marker.
Unfortunately, often applications, even Javac.exe, choke on these byte order marks. Java Readers don't automatically filter them out. There is not much you can do but manually remove them.


http://cache.baidu.com/c?word=java%2Cbom&url=http%3A//tgdem530%2Eblogchina%2Ecom/&b=0&a=1&user=baidu
c、UTF的字节序和BOM
UTF-8以字节为编码单元,没有字节序的问题。UTF-16以两个字节为编码单元,在解释一个UTF-16文本前,首先要弄清楚每个编码单元的字节序。例如收到一个“奎”的Unicode编码是594E,“乙”的Unicode编码是4E59。如果我们收到UTF-16字节流“594E”,那么这是“奎”还是“乙”?

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。

UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8编码是EF BB BF(读者可以用我们前面介绍的编码方法验证一下)。所以如果接收者收到以EF BB BF开头的字节流,就知道这是UTF-8编码了。

Windows就是使用BOM来标记文本文件的编码方式的。


原来BOM是在文件的开始加了几个字节作为标记。有了这个标记,一些协议和系统才能识别。好,看看怎么加上这写字节。
终于在这里找到了
http://mindprod.com/jgloss/encoding.html 
UTF-8 
8-bit encoded Unicode. neé UTF8. Optional marker on front of file: EF BB BF for reading. Unfortunately, OutputStreamWriter does not automatically insert the marker on writing. Notepad can't read the file without this marker. Now the question is, how do you get that marker in there? You can't just emit the bytes EF BB BF since they will be encoded and changed. However, the solution is quite simple. prw.write( 'ufeff' ); at the head of the file. This will be encoded as EF BB BF.
DataOutputStreams have a binary length count in front of each string. Endianness does not apply to 8-bit encodings. Java DataOutputStream and ObjectOutputStream uses a slight variant of kosher UTF-8. To aid with compatibility with C in JNI, the null byte 'u0000' is encoded in 2-byte format rather than 1-byte, so that the encoded strings never have embedded nulls. Only the 1-byte, 2-byte, and 3-byte formats are used. Supplementary characters, (above 0xffff), are represented in the form of surrogate pairs (a pair of encoded 16 bit characters in a special range), rather than directly encoding the character.
 
prw.write( 'ufeff' );就是这个。
于是我的代码变为:
public void htmlWrite(String charsetName) {
        try {
            out = new BufferedWriter(new OutputStreamWriter(
                        new FileOutputStream(outFileName), "UTF-8"));
            out.write('ufeff');
            out.write(res);
            out.flush();

            if (out != null) {
                out.close();
            }
        } catch (Exception e) {
            try {
                if (out != null) {
                    out.close();
                }
            } catch (IOException e1) {
                System.out.print("write errors!" + e);
            }

            System.out.print("write errors!" + e);
        }
    }
问题解决。


本文出处:http://blog.sina.com.cn/s/blog_3e9d2b350100as0b.html

免责声明:文章转载自《UTF-8 的BOM带来的麻烦》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇处理移动端click事件300ms延迟的好方法—FastClick区块链 框架 Substrate 初探下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Qt5字符串编码转换学习

目录 1、通过Python3示例探索常用字符串编码 UTF8 ANSI Unicode 小结 2、Qt5中使用QTextCodec进行编码转换小结 1、通过Python3示例探索常用字符串编码 下面,我们通过Python3代码来了解一下字符串编码的小秘密: 首先,我们定义一个字符串aha123 aha123 = "啊哈123" 然后...

JS编码转换[转载]

//转化成十六进制, 调用的是vbscript的Hex函数 function Hex(n) {    c = n;  execScript("c = Hex(c)", "vbscript");  return c; } //返回文字的AscaII编码, 调用的是vbscript的Asc函数 function Asc(s) {  c = s;  exec...

ArcMap 1 矢量数据和栅格数据

GIS概念中有相当多的数据文件格式,我们经常接触到的数据格式可以大致分为“栅格数据”与“矢量数据”这两类。这两类数据分别对应着不同的应用场景,我们通常使用“栅格数据”来当作底图,示意地理构造物(如山地、河流、湖泊、建筑物、道路等)的空间形态(如形状、位置、大小等),并可以进行一些简易的空间分析;使用“矢量数据”来参与业务逻辑的实现与分析,进行复杂的空间分析...

【转】一个URL编码和解码的C++类

下面的代码实现了一个用于C++中转码的类strCoding。里面有UTF8、UNICODE、GB2312编码的互相转换。 .H文件: #pragma once #include <iostream> #include <string> #include <windows.h> using namespace std;...

Unicode(UTF-8, UTF-16)令人混淆的概念

为啥需要Unicode       我们知道计算机其实挺笨的,它只认识0101这样的字符串,当然了我们看这样的01串时肯定会比较头晕的,所以很多时候为了描述简单都用十进制,十六进制,八进制表示.实际上都是等价的,没啥太多不一样.其他啥文字图片之类的其他东东计算机不认识.那为了在计算机上表示这些信息就必须转换成一些数字.你肯定不能想怎么转换就怎么转,必须得有...

Python字符编码

字符编码 计算机只认识数字,我们平时在使用计算机时,用的都是人类能读懂的字符(用高级语言编程的结果也无非是在文件内写了一堆字符),如何能让计算机读懂人类的字符?必须经过一个过程: 字符--------(翻译过程)------->数字 这个过程实际就是一个字符如何对应一个特定数字的标准,这个标准称之为字符编码 一、存取文件的原理(nodepad++,...