【轉】徹底解決Asp.net文件下載(Response.WriteFile)時文件名的中文亂碼和空格異常問題


在 asp.net 項目中,我們可以很方便地使用 Response.WriteFile() 方法向客戶端輸出一個文件。
實際使用 asp.net
向客戶端輸出文件流時,卻出現了異常:
1、空格問題,當原文件的文件名中含有空格時,將引發客戶端獲取到的文件名與服務器端不一致。Spaces cannot
be supported by some browsers
2、中文字符亂碼,准確的是非 ASCII 字符亂碼,當原文件的文件名中含有非 ASCII
字符時,將引發客戶端獲取到的文件名錯亂。Non-US-ASCII characters cause incorrect
result
3、一些特殊字符不能被正常輸出(當然這里我並不是那些不常見的符號)

 

問題現象:

當原文件名包含空格時,默認將被改成下划線,即“_”;如果我們在輸出文件時對文件名使用
UrlEncode() 對其進行編碼,空格將變成加號,即“+”。

當原文件名包含中文或其他非英文字符時,由於編碼的錯誤,默認情況很糟糕,竟然完全是無法辨識的亂碼;如果我們在輸出文件時對文件名進行 UrlEncode()
對其進行編碼,這些中文將能正確地被顯示;
但注意,問題並沒有完。在Opera 或 Firefox 中,不需要經過 UrlEncode()
即能正確地顯示了;不幸地是,如果經過了 UrlEncode(),它們將無法正確地解析。

問題的解決

我們可以總結如下規律:
Internet Explorer
能在客戶端已經UrlEncode() 的字符,包括空格在內;而 Opera 等其他瀏覽器可以解析未經 UrlEncode()
的直接輸出的字符(這意味着,對於使用Opera或其他客戶端的客戶,我們不應該對它進行
UrlEncode()編碼)

為了正確地編碼,我參考一位外國人士的代碼,使用了並改進了16進制編碼方法。
參考下面的代碼,可以大部分的解決問題。由於
Firefox 不支持空格,所以以下代碼對於 Firefox ,仍不能完成具有空格的文件名的正確輸出:

在輸出文件地地方使用的代碼:

if (Request.UserAgent.Contains("MSIE") || Request.UserAgent.Contains("msie")) 
{         
      // 如果客戶端使用 Microsoft Internet Explorer,則需要編碼
    fileName = ToHexString(fileName); 
}

 

 應該置於上述代碼同一文件或可訪問的其他類的幾個函數:

       /// <summary>
        /// 為字符串中的非英文字符編碼
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static string ToHexString(string s)
        {
            char[] chars = s.ToCharArray();
            StringBuilder builder = new StringBuilder();
            for (int index = 0; index < chars.Length; index++)
            {
                bool needToEncode = NeedToEncode(chars[index]);
                if (needToEncode)
                {
                    string encodedString = ToHexString(chars[index]);
                    builder.Append(encodedString);
                }
                else
                {
                    builder.Append(chars[index]);
                }
            }

            return builder.ToString();
        }

        /// <summary>
        ///指定 一個字符是否應該被編碼
        /// </summary>
        /// <param name="chr"></param>
        /// <returns></returns>
        private static bool NeedToEncode(char chr)
        {
            string reservedChars = "$-_.+!*'(),@=&";

            if (chr > 127)
                return true;
            if (char.IsLetterOrDigit(chr) || reservedChars.IndexOf(chr) >= 0)
                return false;

            return true;
        }

        /// <summary>
        /// 為非英文字符串編碼
        /// </summary>
        /// <param name="chr"></param>
        /// <returns></returns>
        private static string ToHexString(char chr)
        {
            UTF8Encoding utf8 = new UTF8Encoding();
            byte[] encodedBytes = utf8.GetBytes(chr.ToString());
            StringBuilder builder = new StringBuilder();
            for (int index = 0; index < encodedBytes.Length; index++)
            {
                builder.AppendFormat("%{0}", Convert.ToString(encodedBytes[index], 16));
            }
           return builder.ToString();
        }

此外,針對一些瀏覽器做了一些特殊的處理,已經體現在本文示例代碼的注釋中。此代碼已經能非常完好地解決問題了,在 Internet Explorer
、Opera、Firefox 及 Chrome 中得到的體驗一致,支持中文,支持空格的正常輸出。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM