下载文件时根据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类型列表,并通过正则表达式将其转换为程序代码,粘入了程序中:

这个通过正则表达式转换而来的代码量非常大。

需注意的是,其中有很多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和编码格式信息:

生成下载文件路径

现在有了上面的方法,我们就可以通过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("http://i3.6.cn/cvbnm/7c/15/a3/35ad5275ed17904d4a2d40f3dacea80b.gif"), "image/gif"));

//url中扩展名是gif,但MIME类型实际是image/jpeg的资源。下载后的扩展名是jpe,因为字典MimeDic里存储的对应扩展名就是jpe。

Assert.AreEqual(@"C:\Users\Public\Downloads\35ad5275ed17904d4a2d40f3dacea80b.jpe", 生成下载文件存放路径(d, new Uri("http://i3.6.cn/cvbnm/7c/15/a3/35ad5275ed17904d4a2d40f3dacea80b.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"));

}

文件下载

万事俱备,只欠东风了,让我们来完成下载方法:

时间: 2024-11-03 09:45:09

下载文件时根据MIME类型自动判断保存文件的扩展名的相关文章

asp.net 下载文件时根据MIME类型自动判断保存文件的扩展名_实用技巧

引言 用WebClient下载远程资源时,经常会遇到类似这样的网址: http://www.uushare.com/filedownload?user=icesee&id=2205188 http://www.guaishow.com/u/luanfujie/g9675/ 我们不知道这个Url具体代表的是一个网页,还是某种类型的文件. 而有些Url虽然带有扩展名,但可能是错误的扩展名,常见的比如把gif文件标上了jpg扩展名. 如果我们没法正确判断下载源的文件类型的话,就无法保存为正确的文件格式

艾伟_转载:下载文件时根据MIME类型自动判断保存文件的扩展名

引言 用WebClient下载远程资源时,经常会遇到类似这样的网址: http://www.uushare.com/filedownload?user=icesee&id=2205188 http://www.guaishow.com/u/luanfujie/g9675/ 我们不知道这个Url具体代表的是一个网页,还是某种类型的文件. 而有些Url虽然带有扩展名,但可能是错误的扩展名,常见的比如把gif文件标上了jpg扩展名. 如果我们没法正确判断下载源的文件类型的话,就无法保存为正确的文件格式

急求,eclipse编程时实现当前代码自动复制保存到指定文件的类,方法,打jar包

问题描述 急求,eclipse编程时实现当前代码自动复制保存到指定文件的类,方法,打jar包 先说下需求,编程时总希望把当前正在编写的自认为比较有借鉴意义的代码追加保存到指定文件,留作日后参考,但如果每次都手动复制粘贴,又很麻烦,故思考写个实现该功能的工具类,打成jar包,封装本方法,这样以后不管在哪个项目里敲代码,想保存时就导入自定义的jar包,调用一下该方法就完成了追加保存,简洁方便:然本人初学能力不足,只完成了部分,截图如下,望各位不吝赐教 可以看到主要困难在于获得当前文件的路径名,ecl

image-Image Ready在优化输出时以不同的设置参数保存文件

问题描述 Image Ready在优化输出时以不同的设置参数保存文件 5C 如题,在优化输出时以不同的设置参数保存文件,列表说明各种不同的设置参数导致图像在显示质量和文件大小上的区别.(有代表的比较三种,在线等)

微信网页中上传文件时“只能选择SD卡中的文件”问题

问题描述 微信网页中上传文件时"只能选择SD卡中的文件"问题 解决方案 这个应该是微信上传文件的设置问题吧,我的也是这样. 解决方案二: 微信有jssdk拍照上传接口,可以看看相关文档. 解决方案三: 应该是设置中的问题吧

sql server 类型自动判断和条件检查的备份脚本

根据自己环境自定义了一个备份脚本! 说明: 使用方法:exec master.dbo.fullbackup1 's:\backup','suzhou','full' 0.备份类型只能是full.diff或log,数据库名不能为空 1.通过新建一个历史表记 录每次备份内容 2.检查数据库版本是否为2005以上 3.检查当前用户是否有权 限完成备份 4.会自动检查指定盘符是否存在 5.检查指定格式是否为s:\ 6.如果指定的备份目录不存在proc将自动新建,根据备份类型为full.diff或 log

Struts2写下载功能时,网上找了获取输出文件的名称的方法,有点不明白

问题描述 /** * 获取输出文件的名. * * @return 保存名 */public String getOutName() {try {int index = outName.lastIndexOf(".");String outType = outName.substring(index);String newOutName = outName.substring(0, index - 1);// newOutName=newOutName.substring(0,// ne

[求助]问一个关于远程文件确定的菜鸟问题,怎么判断远程文件和文件夹??

问题描述 我用一个方法得到了FTP上的目录及文件,(用的是WebRequestMethods.Ftp等实现),填充到了一个字符数组中(string[]list)现在,我有一个问题,如果想判断list数组中的每一项是文件还是文件夹呢?请大侠们指点江山. 解决方案 解决方案二:我用过一个办法,就是一般文件都有括展名,所以文件都包含一个字符".",文件夹一般不包含,但是这种方法毕竟不是好的方法,谁还有方法?解决方案三:精神可佳,鼓励一下自己.解决方案四:你得到的时候,能判断文件和文件夹?如果

使用vs2008新建web窗体时,系统无法自动生成代码文件

问题描述 以前创建新的web窗体aspx时都会自动生成一个aspx.cs的文件,但是这两天创建窗体的时候出不来了,重装系统,重新安装vs2008新建窗体还是只有一个aspx没有aspx.cs文件这是怎么回事 解决方案 解决方案二:用了这么多年的vs2008,这种情况没遇到过解决方案三:<%@PageLanguage="C#"AutoEventWireup="true"CodeBehind="admin.aspx.cs"Inherits=&q