今天作文件下載功能模塊,發現幾個問題。git
1. 若是指定的文件名裏包含了空格,FireFox就會截取空格前的部分做爲默認文件名,IE就會在空格位置經過+號填補web
2. 中文字符亂碼,準確的是非 ASCII 字符亂碼,當原文件的文件名中含有非 ASCII 字符時,將引起客戶端獲取到的文件名錯亂瀏覽器
3. 一些特殊字符不能被正常輸出(固然這裏我並非那些不常見的符號)好比「.」在IE下就會變爲「[1].」app
對於這三個問題,網上解決方案已經不少了,但沒有一個完整的能夠解決這些問題測試
要不就是解決了空格問題,但若是有中文了,就出現了亂碼。要不就是解決了中文了,空格就變成「+」了等等………ui
有人說解決第一個問題解決方法很簡單:用雙引號把文件名括起來:google
Response.AppendHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
Response.ContentType = "application/octet-stream";
這樣作仍是會有問題的,在IE中,若是文件名包含兩個'.'的話,它會在第一個點前自動加個"[1]",因而你原來的文件名"Microsoft.App.zip"就變成了" Microsoft[1].App.zip "編碼
出現這個問題的緣由是微軟IE中的BUG(微軟的說明 )spa
對於這個BUG,能夠經過下面的方法解決code
1 if (Request.Browser.Browser.Contains("IE"))
2 {
3 string ext = fileName.Substring(fileName.LastIndexOf('.'));
4 string name = fileName.Remove(fileName.Length - ext.Length);
5 name = name.Replace(".", "%2e");
6 fileName = name + ext;
7 }
8 Response.AppendHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
9 Response.ContentType = "application/octet-stream";
但這樣解決的前提是文件名稱中不能有中文,仍是頗有侷限性啊。
到這是估計有人想說了,爲什麼不用URL編碼文件名稱(HttpUtility.UrlEncode(fileName , System.Text.Encoding.UTF8)))。這個我最先的時候就試過了,經過編碼後,空格所有成了+號了,固然這樣作也就是解決了中文亂碼問題,結果顯示的仍是很不滿意
最後經過google,終於找到老外的一編文章:Display a non-US-ASCII filename in File Download dialog box
如下是他的代碼
1 string encodefileName=ToHexString(fileName); //使用自定義的 Response.AppendHeader("content-disposition", "attachment;filename=" + encodefileName);
2 /// <summary>
3 /// 爲字符串中的非英文字符編碼Encodes non-US-ASCII characters in a string.
4 /// </summary>
5 /// <param name="s"></param>
6 /// <returns></returns>
7 public static string ToHexString(string s)
8 {
9 char[] chars = s.ToCharArray();
10 StringBuilder builder = new StringBuilder();
11 for (int index = 0; index < chars.Length; index++)
12 {
13 bool needToEncode = NeedToEncode(chars[index]);
14 if (needToEncode)
15 {
16 string encodedString = ToHexString(chars[index]);
17 builder.Append(encodedString);
18 }
19 else
20 {
21 builder.Append(chars[index]);
22 }
23 }
24 return builder.ToString();
25 }
26 /// <summary>
27 ///指定一個字符是否應該被編碼 Determines if the character needs to be encoded.
28 /// </summary>
29 /// <param name="chr"></param>
30 /// <returns></returns>
31 private static bool NeedToEncode(char chr)
32 {
33 string reservedChars = "$-_.+!*'(),@=&";
34 if (chr > 127)
35 return true;
36 if (char.IsLetterOrDigit(chr) || reservedChars.IndexOf(chr) >= 0)
37 return false;
38 return true;
39 }
40 /// <summary>
41 /// 爲非英文字符串編碼Encodes a non-US-ASCII character.
42 /// </summary>
43 /// <param name="chr"></param>
44 /// <returns></returns>
45 private static string ToHexString(char chr)
46 {
47 UTF8Encoding utf8 = new UTF8Encoding();
48 byte[] encodedBytes = utf8.GetBytes(chr.ToString());
49 StringBuilder builder = new StringBuilder();
50 for (int index = 0; index < encodedBytes.Length; index++)
51 {
52 builder.AppendFormat("%{0}", Convert.ToString(encodedBytes[index], 16));
53 }
54 return builder.ToString();
55 }
經過他這段代碼,咱們能夠解決掉兩個問題,一個是中文亂碼問題,還有一個是文件名中出現空格的問題,但第三個問題還在困擾着咱們,這該怎麼辦了。難道真的沒有完美的解決辦法嗎?
答案是否認的,咱們經過以上代碼的總結,會發現,將其稍微結合一下,這三個問題就都迎刃而解了。
如下是我給出的解決方案:
1 string encodefileName=ToHexString(fileName); //使用自定義的
2 if (Request.Browser.Browser.Contains("IE"))
3 {
4 string ext = encodefileName.Substring(encodefileName.LastIndexOf('.'));//獲得擴展名
5 string name = encodefileName.Remove(encodefileName.Length - ext.Length);//獲得文件名稱
6 name = name.Replace(".", "%2e"); //關鍵代碼
7 fileName = name + ext;
8 }
9 else
10 {
11 filename = encodefileName;
12 }
13 Response.AppendHeader("content-disposition", "attachment;filename=" + fileName );
經過這樣處理之後,無論是什麼樣的文件名稱均可以解決掉亂碼問題。該方式以經過測試,相似於「中國.黑客 Doc.v1.0.zip」這類文件名,IE,Chrome測試無壓力,其它還未測試。若是有興趣你們能夠在各類瀏覽器上測試一下。還請你們多提意見!