因公司有需求,需要將一個大檔切割成諸多檔上傳,不透過以往upload一次就把檔案大小過大的檔案一次往Server丟,可能造成的一些頻寬、記憶體等問題。
進度條的判斷,可利用signalR在進行搬檔時回傳client端進行顯示,或是直接顯示切割丟檔的進度。
Javascript
<script>
$(function () {
page.init();
});
var page = {
init: function () {
$("#upload").click($.proxy(this.upload, this));
},
upload: function () {
var file = $("#file")[0].files[0],
name = file.name,
size = file.size,
stamp = Date.now(),
succeed = 0;
var ext
var extIndex = name.lastIndexOf('.');
if (extIndex != -1) {
ext = name.substr(extIndex + 1, name.length);
}
var shardSize = 2 * 1024 * 1024, //以2MB为主
shardCount = Math.ceil(size / shardSize); //總切片數
var deferreds = [];
var res = [];
for (var i = 0; i < shardCount; ++i) {
//計算起始與結束位置
var start = i * shardSize,
end = Math.min(size, start + shardSize);
//FormData
var form = new FormData();
form.append("data", file.slice(start, end)); //slice方法用于切出文件的一部分
form.append("name", name);
form.append("stamp", stamp);
form.append("ext", ext);
form.append("size", size);
form.append("total", shardCount); //總數
var indexx = i + 1;
form.append("index", indexx); //目前是第幾個檔
//Ajax提交
deferreds.push(
$.ajax({
url: "@Url.Action("Upload2", "FileHandle")",
type: "POST",
data: form,
async: true, //是否採非同步進行
processData: false,
contentType: false,
success: function (data) {
++succeed;
$("#output").text(succeed + " / " + shardCount);
}
})
);
}
$.when.apply($, deferreds).done(function () {
//待切割檔案上傳全處理完成後,處理後續相關動作
//我自己的處理方式是將input file設為零,只做form data的處理
});
}
};
</script>
Html
<input type="file" id="file" />
<button id="upload">上傳</button>
<span id="output" style="font-size:12px">等待</span>
C# Controller
public ActionResult Upload()
{
string savename = Request["name"];
string stamp = Request["stamp"];
string ext = Request["ext"];
int total = Convert.ToInt32(Request["total"]);
int index = Convert.ToInt32(Request["index"]);
var data = Request.Files["data"];
//保存在磁碟上
string dir = "D:/slicefile";
string file = Path.Combine(dir, stamp + "_" + index);
data.SaveAs(file);
//用目的檔案的個數來判斷是否該開始合併
DirectoryInfo dirInfo = new DirectoryInfo(dir);
var sliceCount = dirInfo.GetFiles(stamp + "_*").Length;
//透過stamp判斷檔案數如同總數則合併
if (sliceCount == total)
{
try
{
file = Path.Combine(dir, stamp + "." + ext);
var fs = new FileStream(file, FileMode.Create);
for (int i = 1; i <= total; ++i)
{
string part = Path.Combine(dir, stamp + "_" + i);
var bytes = System.IO.File.ReadAllBytes(part);
fs.Write(bytes, 0, bytes.Length);
bytes = null;
System.IO.File.Delete(part);
}
fs.Close();
}
catch (Exception)
{
//此做簡化處理,因非同步速度過快,因此導致檔案在判斷總數上會出現異常
//利用try catch進行包住避開
return Json(new { Error = 0 });
}
}
return Json(new { Error = 0 });
}