当前位置: 首页 > 图文教程 > 网络编程 > ASP.NET > asp.net 下载文件时根据MIME类型自动判断保存文件的扩展名

ASP.NET
使用函数传递参数来执行相应的数据库操作
如何实现在窗体和窗体之间进行传递数据
ASP.NET中文显示之两种解决方法
ASP.NET、JSP及PHP之间的抉择
ASP.NET 2.0发送电子邮件中存在的问题
谈谈HtmlControl与WebControl的区别与用途
从ASP.NET 1.1升级到ASP.NET 2.0要考虑的Cookie问题
通过系统配置来提高ASP.NET应用程序的稳定性
妙用ASP2.0中的URL映射改变网址
AJAX实现web页面中级联菜单的设计
ASP.NET跨页面传值技巧总结
再议ASP.NET DataGrid控件中的“添加新行”功能
Geometry 对象浅析
重构CollapsibleSplitter
如何利用.NET Framework使用RSS feed
ASP.NET获取IP与MAC地址的方法
在ASP.NET 2.0中使用样式、主题和皮肤
ASP.NET中为GridView添加删除提示框
ASP.NET 2.0,无刷新页面新境界
看看一个.net版对话框控件

ASP.NET 中的 asp.net 下载文件时根据MIME类型自动判断保存文件的扩展名


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2010-01-10   浏览: 68 ::
收藏到网摘: n/a

如果我们没法正确判断下载源的文件类型的话,就无法保存为正确的文件格式,会给后续操作及人工阅览造成困扰。 所幸的是,WebRequest可以给出下载源的MIME信息,这让我们可以确定文件的真实格式,并以此来决定最终的存储扩展名。( 引言

用WebClient下载远程资源时,经常会遇到类似这样的网址:

http://www.uushare.com/filedownload?user=icesee&id=2205188

http://www.guaishow.com/u/luanfujie/g9675/

我们不知道这个Url具体代表的是一个网页,还是某种类型的文件。

而有些Url虽然带有扩展名,但可能是错误的扩展名,常见的比如把gif文件标上了jpg扩展名。

如果我们没法正确判断下载源的文件类型的话,就无法保存为正确的文件格式,会给后续操作及人工阅览造成困扰。

所幸的是,WebRequest可以给出下载源的MIME信息,这让我们可以确定文件的真实格式,并以此来决定最终的存储扩展名。(MIME是什么?
建立MIME映射字典
我们首先需要做的工作就是建立一个MIME类型到其对应扩展名的映射字典。
我从网上找来了一个MIME类型列表,并通过正则表达式将其转换为程序代码,粘入了程序中:
image
这个通过正则表达式转换而来的代码量非常大。
需注意的是,其中有很多MIME类型相同但扩展名不同的数据,我们在添加到字典时就将多余的不必要记录忽略了,比如高亮处的那三条都是audio/x-aiff类型,那么后两个扩展名都不会添加到字典中,也不会在后续的操作中被使用。
如果你觉得有些类型添加的对应扩展名不是最常见的对应类型的话,就得手动调整代码了。(下文中就出现了这种情况,如text/html对应的是dhtml扩展名,image/jpeg对应的是jpe扩展名)
字典构建完毕之后,就可以通过这样一个方法来获取MIME类型所对应的扩展名了:
string 获取对应扩展名(string ContentType)
{
foreach (var f in MimeDic.Keys)
{
if (ContentType.ToLower().IndexOf(f) >= 0) return MimeDic[f];
}
return null;
}
这里之所以使用IndexOf方法判断,是因为传入的ContentType中可能还包含其他信息,比如编码格式。
题外话:看到网上曾有人抱怨说WebClient下载网页时容易产生乱码,而且又不好读取网页的编码格式,其实WebRequest的ContentType中就包含MIME和编码格式信息:
image
生成下载文件路径
现在有了上面的方法,我们就可以通过MIME类型确定文件的扩展名了。
现在我们将书写一个用于生成下载文件路径的方法,其功能为:
分析文件的源Url,将其文件名部分作为下载文件的文件名。
如果其Url中不含文件名部分(域名或目录形式),则以其目录名为下载文件的文件名。
根据传入的MIME类型自动确定并替换Url中的原始扩展名(如果有的话),以用作下载文件的文件名。
判断传入的存储目录中是否已存在与下载文件名相同的文件,存在的话就进行重命名,直到没有同名文件为止。
功能有点多了,不适合做范例,不过还是很实用的,所以这里就顺道分享出来。
其代码为:

复制代码 代码如下:

string 生成下载文件存放路径(string 存放目录, Uri Uri, string ContentType)
{
var ex = 获取对应扩展名(ContentType);
string up = null;
string upne = null;
if (Uri.LocalPath == "/")
{
//处理Url是域名的情况
up = upne = Uri.Host;
}
else
{
if (Uri.LocalPath.EndsWith("/"))
{
//处理Url是目录的情况
up = Uri.LocalPath.Substring(0, Uri.LocalPath.Length - 1);
upne = Path.GetFileName(up);
}
else
{
//处理常规Url
up = Uri.LocalPath;
upne = Path.GetFileNameWithoutExtension(up);
}
}
var name = string.IsNullOrEmpty(ex) ? Path.GetFileName(up) : upne + "." + ex;
var fn = Path.Combine(存放目录, name);
var x = 1;
while (File.Exists(fn))
{
fn = Path.Combine(存放目录, Path.GetFileNameWithoutExtension(name) + "(" + x++ + ")" + Path.GetExtension(name));
}
return fn;
}

为了验证其效果,我们通过一个单元测试进行评测:
复制代码 代码如下:

[TestMethod]
public void 文件名生成测试()
{
var d = @"C:\Users\Public\Downloads";
//gif格式文件,正常下载
Assert.AreEqual(@"C:\Users\Public\Downloads\35ad5275ed17904d4a2d40f3dacea80b.gif", 生成下载文件存放路径(d, new Uri("/upload/tech/20100110/20100110120004_8d3bba7425e7c98c50f52ca1b52d3735.gif"), "image/gif"));
//url中扩展名是gif,但MIME类型实际是image/jpeg的资源。下载后的扩展名是jpe,因为字典MimeDic里存储的对应扩展名就是jpe。
Assert.AreEqual(@"C:\Users\Public\Downloads\35ad5275ed17904d4a2d40f3dacea80b.jpe", 生成下载文件存放路径(d, new Uri("/upload/tech/20100110/20100110120004_8d3bba7425e7c98c50f52ca1b52d3735.gif"), "image/jpeg"));
//一个带参数的网页url。下载后的扩展名是dhtml,因为字典MimeDic里存储的对应扩展名就是dhtml。
Assert.AreEqual(@"C:\Users\Public\Downloads\filedownload.dhtml", 生成下载文件存放路径(d, new Uri("http://www.uushare.com/filedownload?user=icesee&id=2205188"), "text/html"));
//一个网页url,其格式为目录形式的,没有确切文件名。
Assert.AreEqual(@"C:\Users\Public\Downloads\g9675.dhtml", 生成下载文件存放路径(d, new Uri("http://www.guaishow.com/u/luanfujie/g9675/"), "text/html"));
//域名形式
Assert.AreEqual(@"C:\Users\Public\Downloads\www.g.cn.dhtml", 生成下载文件存放路径(d, new Uri("http://www.g.cn/"), "text/html"));
Assert.AreEqual(@"C:\Users\Public\Downloads\g.cn.dhtml", 生成下载文件存放路径(d, new Uri("http://g.cn"), "text/html"));
}

文件下载
万事俱备,只欠东风了,让我们来完成下载方法:
复制代码 代码如下:

/// <summary>
/// 下载文件到指定目录,并返回下载后存放的文件路径
/// </summary>
/// <param name="Uri">网址</param>
/// <param name="存放目录">存放目录,如果该目录中已存在与待下载文件同名的文件,那么将自动重命名</param>
/// <returns>下载文件存放的文件路径</returns>
public string 下载文件(Uri Uri, string 存放目录)
{
var q = WebRequest.Create(Uri).GetResponse();
var s = q.GetResponseStream();
var b = new BinaryReader(s);
var file = 生成下载文件存放路径(存放目录, Uri, q.ContentType);
FileStream fs = new FileStream(file, FileMode.Create, FileAccess.Write);
fs.Write(b.ReadBytes((int)q.ContentLength), 0, (int)q.ContentLength);
fs.Close();
b.Close();
s.Close();
return file;
}

代码很简单,就不多说了,我们来完成最后的测试:
复制代码 代码如下:

[TestMethod]
public void 文件下载测试()
{
var d = @"C:\Users\Public\Downloads";
//首次下载
Assert.AreEqual(@"C:\Users\Public\Downloads\filedownload.dhtml", 下载文件(new Uri("http://www.uushare.com/filedownload?user=icesee&id=2205188"), d));
//第二次下载,遇到同名文件,自动重命名
Assert.AreEqual(@"C:\Users\Public\Downloads\filedownload(1).dhtml", 下载文件(new Uri("http://www.uushare.com/filedownload?user=icesee&id=2205188"), d));
//下载一个原本是gif类型的文件
Assert.AreEqual(@"C:\Users\Public\Downloads\2naqyw8.gif", 下载文件(new Uri("http://i38.tinypic.com/2naqyw8.jpg"), d));
}

结语
相较WebClient而言,WebRequest拥有更好的可控性,在WebClient无解的时候,就尝试让WebRequest上场吧。
范例源代码和本文的XPS版本打包下载
/upload/tech/20100110/20100110120029_59c33016884a62116be975a9bb8257e3.rar
转载http://skyd.cnblogs.com/