使用HTML5 FormData對象實現大文件分塊上傳(斷點上傳)功能


  FormData是HTML5新增的一個對象,通過FormData對象可以組裝一組用 XMLHttpRequest發送請求的鍵/值對。它可以更靈活方便的發送表單數據,因為可以獨立於表單使用。如果你把表單的編碼類型設置為multipart/form-data ,則通過FormData傳輸的數據格式和表單通過submit() 方法傳輸的數據格式相同。具體用法參考 FormData對象的使用

  實現邏輯:客戶端首先請求接口,獲取一個唯一的UploadID,然后每次按照固定大小讀取文件塊,同時計算需要上傳的總塊數total,將UploadID、total、當前上傳文件塊的下標index、文件名稱以及文件塊上傳到服務端,服務端根據以上參數把文件塊保存到臨時目錄,同時判斷文件塊是否已經全部上傳完,如果已全部上傳,則需要進行合並操作,最后會返回合並后的文件信息。我的例子中,把獲取UploadID的步驟跟上傳放在了一起,上傳接口中會判斷如果UploadID為空並且index為1,則會生成一個UploadID並返回,后續每次上傳都需要帶上UploadID參數。

  一下前端代碼

  前端代碼

 1 @{
 2     Layout = null;
 3 }
 4 
 5 <!DOCTYPE html>
 6 
 7 <html>
 8 <head>
 9     <meta name="viewport" content="width=device-width" />
10     <title>斷點上傳</title>
11     <script src="@Url.Content("~/Scripts/jquery-3.1.1.min.js")"></script>
12 </head>
13 <body>
14     <input id="myFile" type="file">
15     <button onclick="Start()">上傳</button>
16     <button onclick="Pause()">暫停</button>
17     <button onclick="Continue()">繼續</button>
18     <label>當前進度:<span id="progress"></span></label>
19     <script>
20         var uploadId = '';
21         var index = 1;
22         var pause = false; //暫停
23 
24         function Start() {
25             index = 1;
26             uploadId = '';
27             Upload();
28         }
29 
30         function Upload() {
31             var files = document.getElementById('myFile').files;
32             if (files.length < 1) {
33                 alert('請選擇文件~');
34                 return;
35             }
36             var file = files[0];
37             var totalSize = file.size;//文件大小
38             var blockSize = 1024 * 1024 * 2;//塊大小
39             var blockCount = Math.ceil(totalSize / blockSize);//總塊數
40 
41             //創建FormData對象
42             var formData = new FormData();
43             formData.append('fileName', file.name);//文件名
44             formData.append('total', blockCount);//總塊數
45             formData.append('index', index);//當前上傳的塊下標
46             formData.append('uploadId', uploadId);//上傳編號
47             formData.append('data', null);
48 
49             UploadPost(file, formData, totalSize, blockCount, blockSize);
50         }
51 
52         function UploadPost(file, formData, totalSize, blockCount, blockSize) {
53             if (pause) {
54                 return; //暫停
55             }
56             try {
57                 var start = index * blockSize;
58                 var end = Math.min(totalSize, start + blockSize);
59                 var block = file.slice(start, end);
60                 formData.set('data', block);
61                 formData.set('index', index);
62                 formData.set('uploadId', uploadId);
63 
64                 $.ajax({
65                     url: '',
66                     type: 'post',
67                     data: formData,
68                     processData: false,
69                     contentType: false,
70                     success: function (res) {
71                         block = null;
72                         if (res.Code === 1) {
73                             if (index === 1)
74                                 uploadId = res.UploadID;
75 
76                             $('#progress').text((index / blockCount * 100).toFixed(2) + '%');
77                             if (index < blockCount) {
78                                 index++;
79                                 UploadPost(file, formData, totalSize, blockCount, blockSize);
80                             }
81                         }
82                     }
83                 });
84             } catch (e) {
85                 alert(e);
86             }
87         }
88         ///暫停
89         function Pause() {
90             pause = true;
91         }
92         //繼續
93         function Continue() {
94             pause = false;
95             Upload();
96         }
97     </script>
98 </body>
99 </html>
前端代碼

 

  服務端代碼

  1 using System;
  2 using System.IO;
  3 using System.Linq;
  4 using System.Web;
  5 
  6 namespace UploadTest
  7 {
  8     public class UploadHelper
  9     {
 10 
 11         private UploadHelper()
 12         {
 13 
 14         }
 15 
 16         public UploadHelper(string fileRootPath)
 17         {
 18             if (string.IsNullOrWhiteSpace(fileRootPath))
 19                 throw new ArgumentNullException("fileRootPath", "fileRootPath is null");
 20 
 21             FileRootPath = fileRootPath;
 22             BlockRootPath = fileRootPath + "/blocktmp/";
 23         }
 24         /// <summary>
 25         /// 塊文件存儲根路徑
 26         /// </summary>
 27         private string BlockRootPath { get; set; }
 28 
 29         /// <summary>
 30         /// 文件存儲根路徑
 31         /// </summary>
 32         public string FileRootPath { get; set; }
 33 
 34         /// <summary>
 35         /// 分塊上傳
 36         /// </summary>
 37         public UploadResult Upload(string uploadId, int blockCount, int currIndex, string fileName, HttpPostedFileBase file)
 38         {
 39             try
 40             {
 41                 if (file == null)
 42                     return new UploadResult { Msg = "請選擇文件~" };
 43                 if (blockCount < 1)
 44                     return new UploadResult { Msg = "塊數量不能小於1~" };
 45                 if (currIndex < 0)
 46                     return new UploadResult { Msg = "塊數量小於0~" };
 47                 if (string.IsNullOrWhiteSpace(uploadId) && currIndex > 1)
 48                     return new UploadResult { Msg = "上傳編號為空~" };
 49 
 50                 var result = new UploadResult { Code = 1, Msg = "上傳成功~" };
 51 
 52                 //首次上傳需創建上傳編號
 53                 if (string.IsNullOrWhiteSpace(uploadId) || uploadId.Equals("undefind"))
 54                     uploadId = GenerateUploadId();
 55 
 56                 result.UploadID = uploadId;
 57 
 58                 #region ==塊處理==
 59 
 60                 //塊文件名稱
 61                 var blockName = $"{uploadId}_{currIndex}.block";
 62                 //塊文件目錄路徑
 63                 var blockPath = Path.Combine(BlockRootPath, uploadId);
 64                 //塊文件目錄對象
 65                 DirectoryInfo blockDirectoryInfo = Directory.Exists(blockPath) ? new DirectoryInfo(blockPath) : Directory.CreateDirectory(blockPath);
 66                 //塊文件完整路徑
 67                 var blockFullPath = Path.Combine(blockPath, blockName);
 68                 if (File.Exists(blockFullPath))
 69                 {
 70                     //塊已上傳,不做失敗處理
 71                     return new UploadResult { Code = 1, Msg = "該文件塊已上傳~" };
 72                 }
 73 
 74                 file.SaveAs(blockFullPath);
 75 
 76                 #endregion
 77 
 78                 #region ==塊合並處理==
 79 
 80                 //判斷塊文件是否已將上傳完,上傳完合並文件
 81                 if (blockDirectoryInfo.GetFiles().Count().Equals(blockCount))
 82                 {
 83                     var timestamp = DateTime.Now.ToString("yyyMMdd");
 84                     fileName = uploadId + "." + GetExtension(fileName);
 85                     var filePath = Path.Combine(FileRootPath, timestamp);
 86                     if (!Directory.Exists(filePath))
 87                     {
 88                         Directory.CreateDirectory(filePath);
 89                     }
 90                     //完整文件存儲路徑
 91                     var fileFullPath = Path.Combine(filePath, fileName);
 92                     using (var fs = new FileStream(fileFullPath, FileMode.Create))
 93                     {
 94                         for (var i = 1; i <= blockCount; i++)
 95                         {
 96                             var path = Path.Combine(blockPath, $"{uploadId}_{i}.block");
 97                             var bytes = File.ReadAllBytes(path);
 98                             fs.Write(bytes, 0, bytes.Length);
 99                         }
100                         Directory.Delete(blockPath, true);
101 
102                         result.FileInfo = new UploadFileInfo
103                         {
104                             FileName = fileName,
105                             FilePath = Path.Combine(timestamp, fileName)
106                         };
107                     }
108                 }
109 
110                 return result;
111                 #endregion
112             }
113             catch (Exception ex)
114             {
115                 return new UploadResult { Msg = ex.Message };
116             }
117         }
118 
119         /// <summary>
120         /// 生成上傳唯一編號
121         /// </summary>
122         /// <returns></returns>
123         public string GenerateUploadId()
124         {
125             var guid = Guid.NewGuid().ToString();
126             return guid.Replace("-", "");
127         }
128 
129         /// <summary>
130         /// 獲取文件擴展名
131         /// </summary>
132         /// <param name="fileName"></param>
133         /// <returns></returns>
134         public string GetExtension(string fileName)
135         {
136             if (string.IsNullOrWhiteSpace(fileName) || fileName.IndexOf(".") < 0)
137             {
138                 return string.Empty;
139             }
140             var arr = fileName.Split('.');
141             return arr[arr.Length - 1];
142         }
143     }
144     /// <summary>
145     /// 文件上傳結果
146     /// </summary>
147     public class UploadResult
148     {
149         /// <summary>
150         /// 狀態碼 0失敗 1成功
151         /// </summary>
152         public int Code { get; set; }
153         /// <summary>
154         /// 消息
155         /// </summary>
156         public string Msg { get; set; }
157         /// <summary>
158         /// 上傳編號,唯一
159         /// </summary>
160         public string UploadID { get; set; }
161         /// <summary>
162         /// 文件保存信息
163         /// </summary>
164         public UploadFileInfo FileInfo { get; set; }
165 
166     }
167     public class UploadFileInfo
168     {
169         /// <summary>
170         /// 文件保存名稱
171         /// </summary>
172         public string FileName { get; set; }
173         /// <summary>
174         /// 文件保存路徑
175         /// </summary>
176         public string FilePath { get; set; }
177         /// <summary>
178         /// 文件MD5值
179         /// </summary>
180         public string MD5 { get; set; }
181     }
182 }
UploadHelper

 

  Controller代碼

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace UploadTest.Controllers
{
    [RoutePrefix("upload")]
    public class UploadController : Controller
    {
        [Route]
        [HttpGet]
        public ActionResult Index()
        {
            return View();
        }
        [Route]
        [HttpPost]
        public ActionResult Upload(string uploadId,int total,int index,string fileName)
        {
            var helper = new UploadHelper("D:\\Upload");
            var result = helper.Upload(uploadId, total, index, fileName, Request.Files[0]);

            return Json(result);
        }
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM