asp.net 下載文件時(shí)根據(jù)MIME類型自動(dòng)判斷保存文件的擴(kuò)展名
用WebClient下載遠(yuǎn)程資源時(shí),經(jīng)常會(huì)遇到類似這樣的網(wǎng)址:
http://www.uushare.com/filedownload?user=icesee&id=2205188
http://www.guaishow.com/u/luanfujie/g9675/
我們不知道這個(gè)Url具體代表的是一個(gè)網(wǎng)頁(yè),還是某種類型的文件。
而有些Url雖然帶有擴(kuò)展名,但可能是錯(cuò)誤的擴(kuò)展名,常見的比如把gif文件標(biāo)上了jpg擴(kuò)展名。
如果我們沒法正確判斷下載源的文件類型的話,就無法保存為正確的文件格式,會(huì)給后續(xù)操作及人工閱覽造成困擾。
所幸的是,WebRequest可以給出下載源的MIME信息,這讓我們可以確定文件的真實(shí)格式,并以此來決定最終的存儲(chǔ)擴(kuò)展名。(MIME是什么?)
建立MIME映射字典
我們首先需要做的工作就是建立一個(gè)MIME類型到其對(duì)應(yīng)擴(kuò)展名的映射字典。
我從網(wǎng)上找來了一個(gè)MIME類型列表,并通過正則表達(dá)式將其轉(zhuǎn)換為程序代碼,粘入了程序中:
這個(gè)通過正則表達(dá)式轉(zhuǎn)換而來的代碼量非常大。
需注意的是,其中有很多MIME類型相同但擴(kuò)展名不同的數(shù)據(jù),我們?cè)谔砑拥阶值鋾r(shí)就將多余的不必要記錄忽略了,比如高亮處的那三條都是audio/x-aiff類型,那么后兩個(gè)擴(kuò)展名都不會(huì)添加到字典中,也不會(huì)在后續(xù)的操作中被使用。
如果你覺得有些類型添加的對(duì)應(yīng)擴(kuò)展名不是最常見的對(duì)應(yīng)類型的話,就得手動(dòng)調(diào)整代碼了。(下文中就出現(xiàn)了這種情況,如text/html對(duì)應(yīng)的是dhtml擴(kuò)展名,image/jpeg對(duì)應(yīng)的是jpe擴(kuò)展名)
字典構(gòu)建完畢之后,就可以通過這樣一個(gè)方法來獲取MIME類型所對(duì)應(yīng)的擴(kuò)展名了:
string 獲取對(duì)應(yīng)擴(kuò)展名(string ContentType)
{
foreach (var f in MimeDic.Keys)
{
if (ContentType.ToLower().IndexOf(f) >= 0) return MimeDic[f];
}
return null;
}
這里之所以使用IndexOf方法判斷,是因?yàn)閭魅氲腃ontentType中可能還包含其他信息,比如編碼格式。
題外話:看到網(wǎng)上曾有人抱怨說WebClient下載網(wǎng)頁(yè)時(shí)容易產(chǎn)生亂碼,而且又不好讀取網(wǎng)頁(yè)的編碼格式,其實(shí)WebRequest的ContentType中就包含MIME和編碼格式信息:
生成下載文件路徑
現(xiàn)在有了上面的方法,我們就可以通過MIME類型確定文件的擴(kuò)展名了。
現(xiàn)在我們將書寫一個(gè)用于生成下載文件路徑的方法,其功能為:
分析文件的源Url,將其文件名部分作為下載文件的文件名。
如果其Url中不含文件名部分(域名或目錄形式),則以其目錄名為下載文件的文件名。
根據(jù)傳入的MIME類型自動(dòng)確定并替換Url中的原始擴(kuò)展名(如果有的話),以用作下載文件的文件名。
判斷傳入的存儲(chǔ)目錄中是否已存在與下載文件名相同的文件,存在的話就進(jìn)行重命名,直到?jīng)]有同名文件為止。
功能有點(diǎn)多了,不適合做范例,不過還是很實(shí)用的,所以這里就順道分享出來。
其代碼為:
string 生成下載文件存放路徑(string 存放目錄, Uri Uri, string ContentType)
{
var ex = 獲取對(duì)應(yīng)擴(kuò)展名(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
{
//處理常規(guī)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;
}
為了驗(yàn)證其效果,我們通過一個(gè)單元測(cè)試進(jìn)行評(píng)測(cè):
[TestMethod]
public void 文件名生成測(cè)試()
{
var d = @"C:\Users\Public\Downloads";
//gif格式文件,正常下載
Assert.AreEqual(@"C:\Users\Public\Downloads\35ad5275ed17904d4a2d40f3dacea80b.gif", 生成下載文件存放路徑(d, new Uri("/upload/2009-11/20091112231022422.gif"), "image/gif"));
//url中擴(kuò)展名是gif,但MIME類型實(shí)際是image/jpeg的資源。下載后的擴(kuò)展名是jpe,因?yàn)樽值銶imeDic里存儲(chǔ)的對(duì)應(yīng)擴(kuò)展名就是jpe。
Assert.AreEqual(@"C:\Users\Public\Downloads\35ad5275ed17904d4a2d40f3dacea80b.jpe", 生成下載文件存放路徑(d, new Uri("/upload/2009-11/20091112231022422.gif"), "image/jpeg"));
//一個(gè)帶參數(shù)的網(wǎng)頁(yè)url。下載后的擴(kuò)展名是dhtml,因?yàn)樽值銶imeDic里存儲(chǔ)的對(duì)應(yīng)擴(kuò)展名就是dhtml。
Assert.AreEqual(@"C:\Users\Public\Downloads\filedownload.dhtml", 生成下載文件存放路徑(d, new Uri("http://www.uushare.com/filedownload?user=icesee&id=2205188"), "text/html"));
//一個(gè)網(wǎng)頁(yè)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"));
}
文件下載
萬(wàn)事俱備,只欠東風(fēng)了,讓我們來完成下載方法:
/// <summary>
/// 下載文件到指定目錄,并返回下載后存放的文件路徑
/// </summary>
/// <param name="Uri">網(wǎng)址</param>
/// <param name="存放目錄">存放目錄,如果該目錄中已存在與待下載文件同名的文件,那么將自動(dòng)重命名</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;
}
代碼很簡(jiǎn)單,就不多說了,我們來完成最后的測(cè)試:
[TestMethod]
public void 文件下載測(cè)試()
{
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));
//第二次下載,遇到同名文件,自動(dòng)重命名
Assert.AreEqual(@"C:\Users\Public\Downloads\filedownload(1).dhtml", 下載文件(new Uri("http://www.uushare.com/filedownload?user=icesee&id=2205188"), d));
//下載一個(gè)原本是gif類型的文件
Assert.AreEqual(@"C:\Users\Public\Downloads\2naqyw8.gif", 下載文件(new Uri("http://i38.tinypic.com/2naqyw8.jpg"), d));
}
結(jié)語(yǔ)
相較WebClient而言,WebRequest擁有更好的可控性,在WebClient無解的時(shí)候,就嘗試讓W(xué)ebRequest上場(chǎng)吧。
范例源代碼和本文的XPS版本打包下載
http://xiazai.jb51.net/200911/yuanma/asp.net_mime_down.rar
轉(zhuǎn)載http://skyd.cnblogs.com/
- ASP.NET Web Api 2實(shí)現(xiàn)多文件打包并下載文件的實(shí)例
- ASP.NET(C#) Web Api通過文件流下載文件的實(shí)例
- ASP.NET批量下載文件的方法
- ASP.NET 在下載文件時(shí)對(duì)其重命名的思路及實(shí)現(xiàn)方法
- asp.net C#實(shí)現(xiàn)下載文件的六種方法實(shí)例
- ASP.NET中下載文件的幾種實(shí)例代碼
- 在ASP.NET中下載文件的實(shí)現(xiàn)代碼
- asp.net BackgroundWorker之在后臺(tái)下載文件
- asp.net 下載文件時(shí)輸出文件內(nèi)容
- asp.net Web Services上傳和下載文件(完整代碼)
- ASP.NET實(shí)現(xiàn)從服務(wù)器下載文件問題處理
相關(guān)文章
ASP.NET在上傳文件時(shí)對(duì)文件類型的高級(jí)判斷的代碼
在上傳文件過程中,可以通過修改擴(kuò)展名來逃過文件類型的判斷并實(shí)現(xiàn)上傳,就需要可以驗(yàn)證究竟是什么文件。下面的代碼大家可以測(cè)試下。2009-12-12ASP.NET中Response.BufferOutput屬性的使用技巧
這篇文章介紹了ASP.NET中Response.BufferOutput屬性的使用技巧,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-07-07IIS上部署你的ASP.NET?Core?Web?Api項(xiàng)目及Swagger(圖文)
本篇經(jīng)驗(yàn)將和大家介紹如何在IIS上部署ASP.NET?Core項(xiàng)目,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,希望為初學(xué).NET?CORE的童靴入門有所幫助2023-09-09微信公眾平臺(tái)開發(fā)之認(rèn)證"成為開發(fā)者".Net代碼解析
這篇文章主要為大家詳細(xì)解析了微信公眾平臺(tái)開發(fā)之認(rèn)證"成為開發(fā)者".Net代碼,感興趣的小伙伴們可以參考一下2016-06-06用Html5與Asp.net MVC上傳多個(gè)文件的實(shí)現(xiàn)代碼
Html 5 的有一些File API,對(duì)Form表單增強(qiáng)的特性,讓我們輕松支持多文件上傳,看下面的Html片斷代碼2012-08-08獲取遠(yuǎn)程網(wǎng)頁(yè)的內(nèi)容之二(downmoon原創(chuàng))
獲取遠(yuǎn)程網(wǎng)頁(yè)的內(nèi)容之二(downmoon原創(chuàng))...2007-03-03.Net彈性和瞬態(tài)故障處理庫(kù)Polly實(shí)現(xiàn)彈性策略
這篇文章介紹了.Net彈性和瞬態(tài)故障處理庫(kù)Polly實(shí)現(xiàn)彈性策略的方法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06