來自:農碼一生
連結:https://www.cnblogs.com/zhaopei/p/upload.html
作為程式員的我們,經常會要用到檔案的上傳和下載功能。到了需要用的時候,各種查資料。有木有..有木有…。為了方便下次使用,這裡來做個總結和備忘。
利用表單實現檔案上傳
最原始、最簡單、最粗暴的檔案上傳。
前端程式碼:
//方式1
【註意】
1、需要post提交
2、enctype=”multipart/form-data” (傳輸檔案)
3、需要提交的表單元素需要設定 name 屬性
後臺程式碼:
public ActionResult SaveFile1()
{
if (Request.Files.Count > 0)
{
Request.Files[0].SaveAs(Server.MapPath(“~/App_Data/”) + Request.Files[0].FileName);
return Content(“儲存成功”);
}
return Content(“沒有讀到檔案”);
}
表單非同步上傳(jquery.form外掛)
雖然上面的方式簡單粗暴,但是不夠友好。頁面必然會掃清。難以實現停留在當前頁面,並給出檔案上傳成功的提示。
隨著時間的流逝,技術日新月異。ajax的出現,使得非同步檔案提交變得更加容易。
下麵我們利用jquery.form外掛來實現檔案的非同步上傳。
首先我們需要匯入jquery.js和jquery.form.js
前端程式碼:
//方式2(透過ajaxForm系結ajax操作)
$(function () {
$(‘#form2’).ajaxForm({
success: function (responseText) {
alert(responseText);
}
});
});
//方式3(透過ajaxSubmit直接執行ajax操作)
$(function () {
$(“.but2”).click(function () {
$(‘#form2’).ajaxSubmit({
success: function (responseText) {
alert(responseText);
}
});
});
});
後臺程式碼:
public string SaveFile2()
{
if (Request.Files.Count > 0)
{
Request.Files[0].SaveAs(Server.MapPath(“~/App_Data/”) + Path.GetFileName(Request.Files[0].FileName));
return “儲存成功”;
}
return “沒有讀到檔案”;
}
原理:我們很多時候使用了外掛,就不管其他三七二十一呢。
如果有點好奇心,想想這個外掛是怎麼實現的。隨便看了看原始碼一千五百多行。我的媽呀,不就是個非同步上傳嗎,怎麼這麼複雜。
難以看出個什麼鬼來,直接斷點除錯下吧。
原來外掛內部有iframe和FormData不同方式來上傳,來適應更多版本瀏覽器。
模擬表單資料上傳(FormData)
iframe這東西太噁心。我們看到上面可以利用FormData來上傳檔案,這個是Html 5 才有的。下麵我們自己也來試試把。
前端程式碼:
//方式4
$(“.btnNotForm”).click(function () {
var formData = new FormData();//初始化一個FormData物件
formData.append(“files”, $(“.notFormFile”)[0].files[0]);//將檔案塞入FormData
$.ajax({
url: “/Home/SaveFile2”,
type: “POST”,
data: formData,
processData: false, // 告訴jQuery不要去處理髮送的資料
contentType: false, // 告訴jQuery不要去設定Content-Type請求頭
success: function (responseText) {
alert(responseText);
}
});
});
後的程式碼:(不變,還是上例程式碼)
public string SaveFile2()
{
if (Request.Files.Count > 0)
{
Request.Files[0].SaveAs(Server.MapPath(“~/App_Data/”) + Path.GetFileName(Request.Files[0].FileName));
return “儲存成功”;
}
return “沒有讀到檔案”;
}
我們看到,FormData物件也只是在模擬一個原始的表單格式的資料。那有沒有可能不利用表單或表單格式來上傳檔案呢?答案是肯定的。
前端程式碼:
//方式5
$(“.btnFile5”).click(function () {
$.ajax({
url: “/Home/SaveFile4”,
type: “POST”,
data: $(“#file5”)[0].files[0],
processData: false, // 告訴jQuery不要去處理髮送的資料
contentType: false, // 告訴jQuery不要去設定Content-Type請求頭
success: function (responseText) {
alert(responseText);
}
});;
});
後臺程式碼:
public string SaveFile4()
{
//這裡發現只能得到一個網路流,沒有其他資訊了。(比如,檔案大小、檔案格式、檔案名等)
Request.SaveAs(Server.MapPath(“~/App_Data/SaveFile4.data”) + “”, false);
return “儲存成功”;
}
細心的你發現沒有了表單格式,我們除了可以上傳檔案流資料外,不能再告訴後臺其他資訊了(如檔案格式)。
到這裡,我似乎明白了以前上傳檔案為什麼非得要用個form包起來,原來這隻是和後臺約定的一個傳輸格式而已。
其實我們單純的用jq的ajax傳輸文字資料的時候,最後也是組裝成了form格式的資料,如:
$.ajax({
data: { “userName”: “張三” }
分片上傳
在知道了上面的各種上傳之後,我們是不是就滿於現狀了呢?no,很多時候我們需要傳輸大檔案,一般伺服器都會有一定的大小限制。
某天,你發現了一個激情小電影想要分享個大家。無奈,高畫質檔案太大傳不了,怎麼辦?我們可以化整為零,一部分一部分的傳嘛,也就是所謂的分片上傳。
前端程式碼:
//方式6
$(“.btnFile6”).click(function () {
var upload = function (file, skip) {
var formData = new FormData();//初始化一個FormData物件
var blockSize = 1000000;//每塊的大小
var nextSize = Math.min((skip + 1) * blockSize, file.size);//讀取到結束位置
var fileData = file.slice(skip * blockSize, nextSize);//擷取 部分檔案 塊
formData.append(“file”, fileData);//將 部分檔案 塞入FormData
formData.append(“fileName”, file.name);//儲存檔案名字
$.ajax({
url: “/Home/SaveFile6”,
type: “POST”,
data: formData,
processData: false, // 告訴jQuery不要去處理髮送的資料
contentType: false, // 告訴jQuery不要去設定Content-Type請求頭
success: function (responseText) {
$(“.result”).html(“已經上傳了” + (skip + 1) + “塊檔案”);
if (file.size <= nextSize) {//如果上傳完成,則跳出繼續上傳
alert(“上傳完成”);
return;
}
upload(file, ++skip);//遞迴呼叫
}
});
};
var file = $(“#file6”)[0].files[0];
upload(file, 0);
});
後臺程式碼:
public string SaveFile6()
{
//儲存檔案到根目錄 App_Data + 獲取檔案名稱和格式
var filePath = Server.MapPath(“~/App_Data/”) + Request.Form[“fileName”];
//建立一個追加(FileMode.Append)方式的檔案流
using (FileStream fs = new FileStream(filePath, FileMode.Append, FileAccess.Write))
{
using (BinaryWriter bw = new BinaryWriter(fs))
{
//讀取檔案流
BinaryReader br = new BinaryReader(Request.Files[0].InputStream);
//將檔案留轉成位元組陣列
byte[] bytes = br.ReadBytes((int)Request.Files[0].InputStream.Length);
//將位元組陣列追加到檔案
bw.Write(bytes);
}
}
return “儲存成功”;
}
相對而言,程式碼量多了一點,複雜了一點。不過相對於網上的其他分片上傳的程式碼應該要簡單得多(因為這裡沒有考慮多檔案塊同時上傳、斷點續傳。那樣就需要在後臺把檔案塊排序,然後上傳完成按序合併,然後刪除原來的臨時檔案。有興趣的同學可以自己試試,稍候在分析上傳外掛webuploader的時候也會實現)。
效果圖:
【說明】:如果我們想要上傳多個檔案怎麼辦?其實H5中也提供了非常簡單的方式。直接在input裡面標記multiple,,然後我們後臺接收的也是一個陣列Request.Files。
使用HTML5 拖拽、貼上上傳
只能說H5真是強大啊,許可權越來越大,操作越來越牛逼。
前端程式碼(拖拽上傳):