【转】彻底解决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 中得到的体验一致,支持中文,支持空格的正常输出。

优质内容筛选与推荐>>
1、dubbox
2、FTP上传心得
3、每日英语:Consumer Lifestyles: China’s Middle Class
4、【统计】Z-score
5、python2与python3下的base64模块


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn