Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 557|回复: 0

【转】彻底解决Asp.net文件下载(Response.WriteFile)时文件名的中文乱码和空格异常问题

[复制链接]
  • TA的每日心情
    奋斗
    2024-4-6 11:05
  • 签到天数: 748 天

    [LV.9]以坛为家II

    2034

    主题

    2092

    帖子

    70万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    705612
    发表于 2021-8-27 15:46:31 | 显示全部楼层 |阅读模式

    在 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...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-4-29 03:33 , Processed in 0.071209 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表