最近在做的一个项目中要用到文件上传下载,初看到这个东西,感觉太简单,但是真正去做了才知道,很多东西只有去做了才知道什么叫做复杂。首先,我们先不直接切入主题,先来解决一下朋友们经常会碰到在做.NET开发时候传递中文参数时候出现乱码的问题,然后引申到我们的流形式文件上传下载。开整……
在做ASP.NET开发时,URL如果要传递中文参数,有时候会报错,会出现乱码。比如在YeanJay.aspx?parm1=中国。在Request.QueryString时,可能会出现乱码。解决的办法如下:
1. 通过设置Web.config指定ASP.NET应用程序默认的请求和响应编码
1
<system.web>
2
<globalization requestEncoding="gb2312" responseEncoding="gb2312" culture="zh-CN" fileEncoding="gb2312" />
3
</system.web>
2. 通过设置aspx页面head指定ASP.NET页面的请求和响应编码
1
<head runat="server">
2
<title></title>
3
<meta http-equiv="Content-Type" content="text/html;charset=gb2312">
4
</head>
3.在传递中文之前,对将要传递的中文参数进行编码,在接受时在进行解码
1)通过在HTML中的用户控件编码:HttpUtility.UrlEncode
1
<asp:HyperLink ID="HyperLink1" runat="server"
2
NavigateURL='<%# "YeanJay.aspx?name=" + HttpUtility.UrlEncode("戚应杰", System.Text.Encoding.GetEncoding("GB2312")) %>' >传给Ken</asp:HyperLink>
2)在服务器端的编码:Server.UrlEncode
1
protected void btnTrans_Click(object sender,EventArgs e)
2
{
3
string Name="戚应杰";
4
Response.Redirect("YeanJay.aspx?name="+Server.UrlEncode(Name));
5
}
3)在客户端JavaScript编码传输

Code
1
<head runat="server">
2
<title>JavaScript</title>
3
4
<script language="JavaScript">
5
function GoUrl()
6
{
7
var name = "戚应杰";
8
location.href = "YeanJay.aspx?name="+escape(name);
9
}
10
</script>
11
</head>
12
接收上面这三种编码方式传递过来的值,并且解码:

Code
1
protected void Page_Load(object sender, EventArgs e)
2

{
3
if (Request["name"] != null)
4
{
5
//接收两种方式传过来的值
6
string Name = Request["name"];
7
Response.Write(Server.UrlDecode(Name));
8
}
9
}
一般来说,只要设置了Web.config文件就可以了。但是如果你用JS来调用WS的话,有时候设置Web.config文件会失效。
如果还是不行,那么就让机器环境支持中文
(1)将页面用记事本,然后选中“另存为”并选择“UTF-8”作为编码方式,而不是默认的ANSI。
(2)打开注册表,确保HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Inetinfo\Parameters\FavorDBCS值设置为0。
(3)修改该数值后,必须运行IISRESET以重新启动IIS服务。
这样就可以保证传递的中文参数可以识别了。
那么接下来就上面的那个中文参数编码的方式,让我想到最近的项目中流形式文件存储与读取。
首先先来做文件上传:

Code
1
2
string send = Convert.ToBase64String(filMyFile.FileBytes);
3
int fileLength = filMyFile.PostedFile.ContentLength;
4
if (fileLength == 0)
5
{
6
ScriptManager.RegisterStartupScript(this, typeof(Page), "opennewwindow", "alert(\"不能上传空文件!\")", true);
7
return;
8
}
9
//DataService ser = new DataService();
10
DataService.DataService service = new Hiktb.Monitor.Web.DataService.DataService();
11
service.Url = ConfigurationManager.AppSettings["UploadUrl"];
12
PowerGridManager pgm = new PowerGridManager();
13
14
//ser.Url = "http://localhost/Sendweb/DataService.asmx";
15
try
16
{
17
service.UploadFile(filMyFile.FileName, FileType.SelectedValue.Trim(), AdminUnit.SelectedValue.Trim(), send);
18
ScriptManager.RegisterStartupScript(this, typeof(Page), "opennewwindow", "alert(\"上传成功!\")", true);
19
}
20
catch (Exception ex)
21
{
22
ScriptManager.RegisterStartupScript(this, typeof(Page), "opennewwindow", "alert(\"上传不成功!\")", true);
23
}
24
}
25
else
26
{
27
ScriptManager.RegisterStartupScript(this, typeof(Page), "opennewwindow", "alert(\"请选择一个文件!\")", true);
28
}
这里的文件上传没有什么问题。首先是获取filMyFile这个文件上传控件里面的文件内容,然后对文件内容进行编码。然后通过调用UpLoadFile函数来上传文件。上传文件非常顺利。
然后就是下载文件:
一开始项目中用到了是用临时目录就是先从数据库中取出流然后生成一个文件,然后将文件放到一个临时目录中,那样的话万一文件一多,那么临时目录中的文件就非常多,然后就客户需求开始变化,说不要设置临时目录。
设置临时目录的Code如下:

Code
1
生成附件,并下载到客户端
2
string url = "GetFile.aspx?id=" + id;
3
4
Response.Redirect(url);
5
6
string TempPath = Request.PhysicalApplicationPath + "Temp/";
7
if (Directory.Exists(TempPath) == false) Directory.CreateDirectory(Request.PhysicalApplicationPath + "Temp/");
8
9
string url = Request.ApplicationPath + "/Temp/" + ds.Tables[0].Rows[0]["FileName"];
10
string name = TempPath + ds.Tables[0].Rows[0]["FileName"];
11
12
FileStream outputStream = new FileStream(name, FileMode.Create);
13
outputStream.Write((byte[])ds.Tables[0].Rows[0]["FileContent"], 0, ((byte[])ds.Tables[0].Rows[0]["FileContent"]).Length);
14
outputStream.Close();
15
Response.Write("<script>window.open('" + url + "')</script>");
唯一不变的就是变化啊!!客户要变,我就变。然后就想,直接用流输出吧。
一阵百度,Google代码是一堆,能用的没几个。那没几个里面能实现的就更没了。
开整……就流呗……
又来一段代码

Code
1
byte[] b2 = (byte[])ds.Tables[0].Rows[0]["FileContent"];
2
string name = (string)ds.Tables[0].Rows[0]["FileName"].ToString().Trim() ;
3
4
string typelower = name.Substring(name.LastIndexOf(".")).Trim().ToLower();
5
string Type = checktype(typelower);
6
string FileNameNew = name.Replace(typelower,"").ToString().Trim();
7
Response.Clear();
8
9
Response.AppendHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(FileNameNew.Trim() + typelower, System.Text.Encoding.UTF8));
11
Response.AddHeader("Content-Length ", b2.Length.ToString());
12
Response.ContentType = Type;
13
14
Response.BinaryWrite(b2);
15
Response.End();
16
这样之后然后就疯狂的报错。说不能识别。丫丫的,肯定是编码问题。
然后就是如果是txt文件不能下载,只能直接在浏览器中看。郁闷。郁闷。
不过有个朋友提醒,肯定是编码问题,然后也看了下代码。结果要加一句
Response.ContentEncoding = System.Text.Encoding.UTF8;
也就是把内容也编码了。郁闷结果就像下面的那样了。要提一下的是代码中的那个checktype(typelower)这个是一个判断ContentType的函数。
一般如.doc文件么就是 application/msword。其他的网上找找很多的。
就变成了下面的代码了。问题解决了。所有的文件都能下载。

Code
1
byte[] b2 = (byte[])ds.Tables[0].Rows[0]["FileContent"];
2
string name = (string)ds.Tables[0].Rows[0]["FileName"].ToString().Trim() ;
3
4
string typelower = name.Substring(name.LastIndexOf(".")).Trim().ToLower();
5
string Type = checktype(typelower);
6
string FileNameNew = name.Replace(typelower,"").ToString().Trim();
7
Response.Clear();
8
9
Response.AppendHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(FileNameNew.Trim() + typelower, System.Text.Encoding.UTF8));
10
Response.ContentEncoding = System.Text.Encoding.UTF8;
11
Response.AddHeader("Content-Length ", b2.Length.ToString());
12
Response.ContentType = Type;
13
14
Response.BinaryWrite(b2);
15
Response.End();
16
总结: 其实无非就是用到了一个知识点,就是编码。其实知识之间很融汇贯通的。同样是编码,在很多地方用到。