【转】ASP.NET 文件下载
当文件上传后就牵涉到文件的下载。那么在asp.net怎样实现文件的下载呢?这是我要谈的话题。文件下载就是把用户从客户端上传的文件下载到本地。这里牵涉到几个问题:这里上传的文件保存在什么地方。有几种保存的方式?
一般来说上传的文件都保存在服务器上,可以是FTP服务器,web服务器,根据具体情况有所不同。但保存的方式不外乎有下面几种:
1.保存到服务器上的数据库中。(二进制格式)
2.保存到服务器上的XML 文件中。(适合小文件存储)
3.保存到服务器磁盘上的文件夹下。(比较通用)
然而在目前的移动项目开发中,我考虑把文件保存到服务器上的文件夹下:这样就引来了几个问题要解决:
1.如果用户在上传文件中,上传了2个一样的文件名不同文件:如:×××立项报告。那岂不是把上一次上传的文件覆盖掉。
当然这样的情况不是没有,如果换成是不同的用户都上传了相同的文件名的文件,那上传到服务器上的最终文件就是后一个上传的覆盖前一个上传的。那岂不是给一个严重的bug!!!.
方案:这个文件当然很好解决的,就是当文件上传到服务器上时候把文件重命名,用GUID来实 现唯一。那么就能保证同一个用户和不同用户上传到服务器上的文件名都不相同,就能保证在服务器上的一个文件夹下同时存在。这样一来这个问题就解决了。然而 这里我们还需要考虑一个问题是:
2.由于上传到服务器是是通过GUID命名的,所以直接连接那文件地址下载下来后的文件名和上传的文件名就不同了。这给用户带来了不好的体验。
方案:为了解决这个问题,我们想到了用Response.WriteFile()来实现:
下面是参考代码:
<asp:GridView ID="GridView1" Width="50%" runat="server" AutoGenerateColumns="False"
EmptyDataText="&
lt;tr><th class='gridHeader' scope='col'>附件名称</th><
th class='gridHeader' scope='col'>上传人</th><
th class='gridHeader' scope='col'>上传时间</th></tr>">
<Columns>
<asp:TemplateField HeaderText="附件名称">
<ItemTemplate>
<span>
<%#DataBinder.Eval(Container.DataItem, "OriginallyFileName")%>
</span>
<a href='&
lt;%#"downfile.aspx?name="+DataBinder.Eval(Container.DataItem,"OriginallyFileName").ToString()+"&
amp;path="+DataBinder.Eval(Container.DataItem,"FilePath")%>
' target="_self" >下载</a>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="InUser" HeaderText="上传人">
<ItemStyle CssClass="itemStyle" HorizontalAlign="Center" />
<HeaderStyle CssClass="gridHeader" />
</asp:BoundField>
<asp:BoundField DataField="InDate" HeaderText="上传时间" DataFormatString="{0:yyyy-MM-dd}"
HtmlEncode="false">
<ItemStyle CssClass="itemStyle" HorizontalAlign="Center" />
<HeaderStyle CssClass="gridHeader" />
</asp:BoundField>
<asp:TemplateField HeaderText="操作">
<ItemTemplate>
<asp:ImageButton runat="server" ID="btnDelete" ImageUrl="~/Images/btnDel.gif" AlternateText="删除"
ImageAlign="Middle" />
</ItemTemplate>
<ItemStyle CssClass="itemStyle" HorizontalAlign="Center" />
<HeaderStyle CssClass="gridHeader" />
</asp:TemplateField>
</Columns>
</asp:GridView>
上面是aspx的代码:下载的链接需要知道一个OriginallyFileName,也就 是文件上传的文件名。而FilePath则是文件上传后保存到服务器上的文件路径。(包括文件名)。上面的代码吧原始的文件名和保存到服务器上的文件路径 传到了downfile.aspx页面,下面我们来看看downfile.aspx页面的代码:
protected void Page_Load(object sender, EventArgs e)
{
string guidname = Request.QueryString["path"];
string reallyname = Request.QueryString["name"];
String FullFileName = Server.MapPath("~/Uploads/" + guidname);
FileInfo info = new FileInfo(FullFileName);
Response.Clear();
Response.ClearHeaders();
Response.Buffer = false;
Response.ContentType = "application/octet-stream";
Response.AppendHeader("Content-Disposition", "attachment;filename="+HttpUtility.UrlEncode(reallyname,System.Text.Encoding.UTF8).Replace("+","%20"));
Response.AppendHeader("Content-Length", info.Length.ToString());
Response.WriteFile(FullFileName);
Response.Flush();
Response.End();
}
有以下几点要注意:
1.使用System.Text.Encoding.UTF来支持中文。(否则加上文件名中包含中文名下载的文件名就成了乱码)
2.使用Replace方法来吧"+"替换成" "(空格),"+"是使用HttpUtility.UrlEncode编码后就把空格转换成了"+",然而"+"不能被浏览器理解为空格无法进行解码,所 以需要手动的吧"+"换成空格(%20)(因为空格的字符编码在浏览器中识别为"%20).这是一个非常容易忽略的小bug,幸好测试人员及早发现了它, 我用Replace方法把它修正了。
页面的效果如下:
当用鼠标左键单击下载链接时候出现:
当用鼠标右键另存为时候,也会出现如上所示的下载对话框:上传的文件名为XmlSerializer.txt,下载下来的文件名也是XmlSerializer.txt问题解决。
下载文件一般用标签A来实现,链接到一个新的页面,如上的(downfile.aspx页面),如果连接到当前页面通过onclick来触发服务器端的事件实现下载。那样的话只能支持通过鼠标左键单击下载,而不能通过右击另存为下载。