HTML5 大文件斷點續傳完整思路整理

利用 html5 的新特性分割文件,爲達到斷點續傳功能

spark.js 獲取文件md5以確保文件的惟一性

流程概述:

(此功能前端共需調用3個接口,分別爲簡稱做 A / B / C)

  1,獲取文件信息:使用HTML5的原生上傳input,選擇文件後,獲取文件的全部信息(文件名、文件總字節數等)

  2,計算總切片:跟後臺約定好單個切片大小,好比1M/片,計算文件總大小/單個切片大小=總切片數

  3,計算文件MD5和每一個切片的MD5:引用spark-md5.min.js來生成MD5,此js的調用能夠獲取文件MD五、切片的MD5和切片的數據

  4,調用A接口查詢從第幾個切片開始上傳:須要向後臺傳入的關鍵參數是文件名、文件總大小、文件的MD5

  5,獲取到初始上傳切片位置,正式開始分片上傳到服務器:從A接口獲取到切片位置後,調用接口B,將切片的MD5和切片數據傳給後臺,此後循環調用接口B,直到最後一切片上傳結束

  6,全部切片上傳結束後,調用接口C將文件存庫
複製代碼

詳細代碼展現:

HTML:

<input type='file' title="" accept=".mp4" 
       name='myfiles' id="mediaFile" class="" onchange="handleFile()" />
複製代碼

獲取文件信息:

function handleFile() {
     var fileInputs = $("input[name='myfiles']")[0]; //獲取input裏的文件信息
     //切割文件的每條內容分別存放
     var name = fileInputs.files[0].name, //文件名 
         size = fileInputs.files[0].size, //文件總字節 
         type = fileInputs.files[0].type, //文件類型 (此功能暫且用不到)
         shardSize = 1024 * 1024, // 每一個切片的總字節數,好比此時以1M爲一個分片
         shardCount = Math.ceil(size / shardSize); //總片數
}
複製代碼

計算整個文件的MD5:(前提是引入了spark.js,下載地址: js-spark-md5

var singleFileData = new Array(); //初始空數組,儲存全部的切片數據
var fileReader = new FileReader(),
   blobSlice = File.prototype.mozSlice || File.prototype.webkitSlice || File.prototype.slice,
   chunkSize = shardSize , //單個切片的總字節數
   chunks = shardCount, //總片數
   currentChunk = 0;
var spark = new SparkMD5.ArrayBuffer();
    fileReader.onload = function (e) {
    //*******獲取分片文件,用於計算全部切片的MD5***
       for (var i = 0; i < chunks; i++) {
         var start = i * chunkSize,
         end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
         var sliceFile = blobSlice.call(file, start, end);
         // 調用此方法,計算每一個切片的MD5
          getChunkMd5(sliceFile, i);
         }
    //*****************************
    spark.append(e.target.result);
    if (currentChunk < chunks) {
       currentChunk++;
       loadNext();
    } else {
      var allFileEnd = spark.end()
       console.log("此值爲整個切片的MD5", allFileEnd)
       //真實MD5值 :allFileEnd=a0ce27800ee7d948422f3fe16e898f22
       // ***調用接口(1),查詢從第幾個切片開始上傳***
       // ***在此處寫接口A的調用方法***
     }
    };
 function loadNext() {
  //計算切片的start,end,用於切割出切片的數據
  var start = currentChunk * chunkSize,
  end = start + chunkSize >= file.size ? file.size : start + chunkSize;
  fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
   //儲存切片的數據
   //判斷若是singleFileData小於總切片數,則繼續往數組添加切片數據
   if (singleFileData.length != chunks) {
    singleFileData.push(blobSlice.call(file, start, end)) //將每一個切片push到空數組裏
   }
  };
  //調用此方法,循環獲取切片數據
  loadNext()
複製代碼

計算切片的MD5:

(此步驟其實能夠省略,但爲了嚴謹後端須要根據前端傳入的切片數據計算出MD5,跟前端傳入的MD5對比)
var mySingleFileMd5 = []; //用於儲存全部切片的MD5
    function getChunkMd5(file, i) {
       var spark = new SparkMD5.ArrayBuffer();
       var fileReader = new FileReader();
       fileReader.onload = function (e) {
         spark.append(e.target.result);
         mySingleFileMd5[i] = spark.end();// 將每一個切片的MD5存起來
         console.log("全部切片的MD5數組=", mySingleFileMd5);
       }
       fileReader.onerror = function () {
         console.warn('oops, something went wrong');
       }
       function loadNext() {
         fileReader.readAsArrayBuffer(blobSlice.call(file, 0, file.size));
       }
   loadNext();
  }
複製代碼

調用接口A後獲取到 PARTINDEX(從第幾個切片開始上傳),接着調用接口B進行上傳,上傳後手動計算進度。

A接口傳參、取參以下:

var params = {
          serviceid: 'wcm61_bigfile',
          methodname: 'startUpload',
          fileName: 手機QQ視頻_20181212094958.mp4,
          fileDigest:  65309fc9684b4eb2f3d281da5ad17b6e,
          fileSize: 100904886,
        };
{
    "MSG":"操做成功",
    "DATA":{
        "TOTALPARTCOUNT":"49",
        "PARTINDEX":"1",  //此字段就是後臺告訴前端從第幾個切片開始上傳
        "PARTSIZE":"2097152",
        "FLAG":"1",
        "FILENAME":"手機QQ視頻_20181212094958.mp4"
     },
    "ISSUCCESS":"true"
}
複製代碼

B接口傳參、取參以下:

var data = singleFileData[partIndex - 1] //切片數據
  var fileName =手機QQ視頻_20181212094958.mp4; //文件名
  var fileDigest = 65309fc9684b4eb2f3d281da5ad17b6e; //文件的MD5
  var partIndex = 1; //切片位置
  var partDigest = ea58e21870ad4c22f2c75645564654b2; //切片的MD5
{
    "filename":"手機QQ視頻_20181212094958.mp4",
    "PARTINDEX":"2",  //下次開始傳第2個切片
    "PARTSIZE":"2097152", //切片大小
    "totalPartCount":"49" //總切片數
    "ISSUCCESS":"1"
}
複製代碼

經過B接口,不斷將切片上傳到服務器,而且實時計算上傳進度

var processNum = 
     parseInt((PARTINDEX - 1) / totalPartCount * 100)  // 已上傳的切片/總切片數 
複製代碼

最終實現靜態效果和接口以下:

效果
相關文章
相關標籤/搜索