很久很久以前,我介紹過CSV與Excel的整合應用,當時同事Daniel補充了一點"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>

Comments

# by Ark

以前爬文~記得如果是xls 像是 Response.ContentEncoding = Encoding.UTF7;可以搞定

# by James

請問你寫入BOM的語法是以下這段嗎? System.IO.StreamWriter sw = new System.IO.StreamWriter( Response.OutputStream, Encoding.UTF8); 我的做法是在輸出主資料前: HttpContext.Current.Response.BinaryWrite(New Byte() {&HEF, &HBB, &HBF})

# by Sally

您好 由於excel2000不支援utf-8,當我改寫成unicode的時候,excle開啟CSV檔時無法將欄位自動分割,所有欄位都在同一個欄位,不過可以確定unicode可正常顯示文字,不知道您是否有研究出來unicode如何讓欄位自動分割??

# by Flora

你好: 我按照你的方式試了之後,發現一個很奇怪的情形。於自己的電腦執行是正常的;但是在別人的電腦執行卻仍是亂碼,而且出現的內容是如你上圖的UTF8woBOM的內容。想請問你是否知道是什麼情形呢?

# by Jeffrey

to Flora, 由你的描述我不太能推論問題所在,建議再蒐集更多測試結果分析,例如: 在更多台機器上測試,有多少的比例會失敗,失敗案例的作業環境有什麼共通點: OS版本、語言(中/英文版)、Excel版本... 等等,如此較容易逼近問題的核心。

# by Kimi

StreamWriter sw = new StreamWriter(fileName, true, System.Text.Encoding.UTF8); 不用再加什麼就完成了!!yoyoyo

# by pcbear

請問此方法可行嗎?我照著做好巷也是亂碼?

# by Jeffrey

to pcbear,可否提供有問題的程式範例及執行環境資訊(Windows, Excel版本),大家可幫忙驗證看看。

# by Doraemon

日文版Win2003SE sp2 日文版Ofc2000 sp3 產出檔案中英日混雜 結果Excel開不了

# by Doraemon

日文版Win2003SE sp2 日文版Ofc2000 sp3 產出檔案中英日混雜 結果Excel開起來只有英文能看 其他都亂碼

# by hiaway

您好: 匯出CSV後,在OFFICE2000打開內容是正常的excel格式且中文也正常。 但在OFFICE2007 或 OFFICE STARTER 2010 打開內文是 HTML CODE且中文是亂碼,不過用記事本開,中文是正常的。 請問這該怎麼解?

# by Jeffrey

to hiaway, Office 2007開啟後出現HTML Code且中文是亂碼 <== 這點不解,想確定一下你的情境開啟的是HTML格式模擬的Excel檔案(並不是CSV)? 還是CSV的內容本身就是HTML?

# by hiaway

hi,Jeffrey 後來周未時我找到問題了,因為我一心想作GridView to CSV,所以將"attachment; filename="的副檔名取為.csv 後來將它改為.xls就沒問題了。真是Sorry。 再說明一下,我提出的問題情況為用啟csv後,它不會以excel的方式顯示,而是在excel上顯示純文字的html code。就像是用記事本開啟這個檔一樣。 不過這個問題在office2000不會產生,在office2007才會。 另外,用office2007開啟這個.xls會多跳出一個「檔案格式與副檔名格式不同」的詢問訊息,在office2000也不會跳出,看過您另一篇文章,這個問題似乎是未有解決方式。

# by Tom

獲益良多, 感恩多謝

# by Fun

謝謝大大~ 用你的方法,解決了匯出若只有一筆,就會亂碼的問題了.

# by 宇夜

感謝你,二支程式,同一個寫法,同一個底層,出來的資料 還是不一樣 快gg了。 感謝黑大 /// <summary> /// 輸出 Excel /// </summary> /// <param name="content">Excel中內容(Table格式)</param> /// <param name="filename">文件名</param> /// <param name="cssText">樣式內容</param> public static void ExportToExcel(string filename, string content, string cssText) { content = string.Format("<style type='text/css'>{0}</style>{1}", cssText, content); HttpContext.Current.Response.Clear(); HttpContext.Current.Response.Buffer = true; HttpContext.Current.Response.Charset = "UTF-8"; HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=" + filename); HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.GetEncoding("GB2312"); HttpContext.Current.Response.ContentType = "application/ms-excel"; //HttpContext.Current.Response.Write(content); 我的 //黑大的 System.IO.StreamWriter sw = new System.IO.StreamWriter( HttpContext.Current.Response.OutputStream, Encoding.UTF8); sw.Write(content); HttpContext.Current.Response.Flush(); HttpContext.Current.Response.End(); }

Post a comment