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

ASP.NET
FreeTextBox(版本3.1.6)在ASP.Net 2.0中使用方法
.NET 常用功能和代码小结
在 .NET Framework 2.0 中未处理的异常导致基于 ASP.NET 的应用程序意外退出
asp.net IList查询数据后格式化数据再绑定控件
asp.net sql存储过程
asp.net 简单实现禁用或启用页面中的某一类型的控件
asp.net(c#)获取内容第一张图片地址的函数
The remote procedure call failed and did not execute的解决办法
ASP.NET 在线文件管理
asp.net 读取并修改config文件实现代码
ASP.NET Cookie 操作实现
asp.net Silverlight中的模式窗体
Silverlight中动态获取Web Service地址
asp.net Silverlight应用程序中获取载体aspx页面参数
asp.net 水晶报表隔行换色实现方法
asp.net 获取Gridview隐藏列的值
手动把asp.net的类生成dll文件的方法
asp.net 使用ObjectDataSource控件在ASP.NET中实现Ajax真分页
动态指定任意类型的ObjectDataSource对象的查询参数
asp.net Md5的用法小结

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


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2010-01-10   浏览: 67 ::
收藏到网摘: 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/