為了識別 Unicode 文件,Microsoft 建議所有的 Unicode 文件應該以 ZERO WIDTH NOBREAK SPACE字符開頭。這作為一個”特征符”或”字節順序標記(byte-order mark,BOM)”來識別文件中使用的編碼和字節順序(big-endian或little-endian),具體的對應關系見下表。
Bytes Encoding Form
00 00 FE FF UTF-32, big-endian
FF FE 00 00 UTF-32, little-endian
FE FF UTF-16, big-endian
FF FE UTF-16, little-endian
EF BB BF UTF-8
以UTF-8無BOM格式編碼,因此要想導出Microsoft Excel可以正常顯示的UTF-8的CSV文件,需要顯式的輸出BOM(EF BB BF,上表的最后一種類型),然后再輸出有效數據。
"Excel只接受ANSI/BIG5編碼的CSV,若存成Unicode,Excel就無法正確顯示"。????
恰巧最近在河道上也看到有人在討論匯出Excel檔時的中文編碼問題,就決定把我后來研究的心得再整理一下。
經驗里要透過ASPX轉出非BIG5的CSV的確會有問題,如以下的程式:
排版顯示純文字
<%@ Page Language= "C#" %>
<script runat= "server" >
protected void Page_Load( object sender, EventArgs e)
{
Response.AddHeader( "content-disposition" ,
"attachment;filename=UnicodeChar.csv" );
Response.ContentType = "application/octet-stream" ;
Response.ContentEncoding = Encoding.UTF8;
Response.Write( "奔,很多牛" );
Response.End();
}
</script>
在上例中,Encoding設為UTF8或Unicode都會得到亂碼,設成BIG5卻又無法顯示"奔"字! 難道本題無解? Excel注定不能開啟Unicode Encoding的CSV?

"身經百戰的Excel無法開啟Unicode CSV?" 直覺上是個不合邏輯的推論。於是我做了一個有趣的實驗:
排版顯示純文字
namespace Lab
{
class ExcelEncTest
{
public static void Test()
{
writeCSV( "Unicode.CSV" ,
Encoding.Unicode);
writeCSV( "UTF8.CSV" ,
Encoding.UTF8);
writeCSV( "UTF8woBOM.CSV" ,
new UTF8Encoding( false ));
}
static void writeCSV( string file, Encoding enc)
{
string s = "奔,很多牛" ;
using (StreamWriter sw =
new StreamWriter(Path.Combine( "C:\\TEMP" , file),
false , enc))
{
sw.WriteLine(s);
sw.Close();
}
}
}
}
三個檔案中,Unicode.csv能正確顯示中文,卻沒有分成兩個欄位。UTF8.csv則中文顯示正常,也明確分成兩欄,看來就是我們期望的結果。至於UTF8woBOM.csv,我用了點技巧,故意不寫入BOM符號,用Excel開啟UTF8woBOM.csv的話有點意思...

有沒有很眼熟? 不就跟我們在第一張圖看到UTF8版的亂碼相同? 換句話說,ASPX傳回UTF8編碼CSV之所以變亂碼是因為少了BOM?
知道了問題所在,要解決就不過是蛋糕一塊! 改用SteamWriter,輸出帶有BOM的CSV內容,Excel就可以正確地顯示萬奔奔騰的CSV啰!
排版顯示純文字
<%@ Page Language= "C#" %>
<script runat= "server" >
protected void Page_Load( object sender, EventArgs e)
{
Response.AddHeader( "content-disposition" ,
"attachment;filename=UnicodeChar.csv" );
Response.ContentType = "application/octet-stream" ;
Response.ContentEncoding = Encoding.UTF8;
System.IO.StreamWriter sw =
new System.IO.StreamWriter(
Response.OutputStream,
Encoding.UTF8);
sw.Write( "奔,很多牛" );
sw.Close();
Response.End();
}
</script>
參考:
http://hi.baidu.com/hlhwpz/item/a702c200ad4e9372bfe97edb
http://blog.darkthread.net/blogs/darkthreadtw/archive/2009/09/06/csv-encoding-again.aspx