UTF-8编码的文件有without BOM和BOM两种格式,最好使用UTF-8 without BOM格式。
-
BOM的含义
BOM,即Byte Order Mark,意为字节序标记。UTF-8编码的文件中,BOM占三个字节。如果用记事本把一个文本文件另存为UTF-8编码方式的话,用UE打开这个文件,切换到十六进制编辑状态就可以看到开头的FFFE了,软件通过BOM来识别这个文件是否是UTF-8编码。
BOM的本意是在UTF-16中用来表示高低字节序列的。在字节流之前有BOM表示采用低字节序列(低字节在前面),而UTF-8不用考虑字节序列,所以其实有无BOM都可以。 -
使用BOM产生的问题
UTF-8以字节为编码单元,没有字节序的问题。UTF-16以两个字节为编码单元,在解释一个UTF-16文本前,首先要弄清楚每个编码单元的字节序。例如收到一个“奎”的Unicode编码是594E,“乙”的Unicode编码是4E59。如果我们收到UTF-16字节流“594E”,那么这是 “奎”还是“乙”?
如果文件保存时,选择了使用BOM,那么就可能会出现headers already sent的问题。因为Web服务器软件可能不认识BOM,所以就把BOM的两个特殊字节当做字符发送给浏览器了。这时再调用session_start()等函数,就会出现headers already sent的问题。所以解决此问题最根本的方法就是在保存UTF-8编码的文件时,不要使用BOM。
微软的记事本,Word等只能正确打开含BOM的UTF8文件,然而UltraEdit却恰恰相反,会把BOM UTF-8文件误认为ascii编码。
UTF-8的BOM是 EFBBBF,因为UE载入UTF-8文件会转成Utf16,上述的EFBBBF 在Utf16中是FFFE(Unicode-LE的BOM),UltraEdit不认识BOM又加多一個BOM,所以有2个FFFE。文件就被它破坏了。
当应用程序的文件使用 UTF8 编码时,在保存文件时,一定要注意 BOM 的问题。那么如何将UTF8 without BOM转换成UTF8呢?
using (TextReader input = new StreamReader(new FileStream(@"C:\Test.properties", FileMode.Open), Encoding.UTF8))
{
using (TextWriter output = new StreamWriter(new FileStream(@"C:\Test2.lmx", FileMode.Create), Encoding.UTF8))
{
int BufferSize = 8096;
char[] buffer = new char[i];
int len;
while ((len = input.Read(buffer, 0, i)) > 0)
{
output.Write(buffer, 0, len);
}
input.Close();
}
}
微软的记事本就是在 UTF-8 文件开头加 BOM,所以最好不要用记事本来编辑UTF-8文件。
推荐使用 Notepad++ 并将编码设为UTF-8 without BOM 来进行编辑,也可以使用其它文本编辑软件转储为UTF-8 without BOM 格式。