天天看點

如何實作檔案分片上傳[顯示檔案上傳進度]

希望有一天大家都能在借鑒中創新

最近沒有在弄這個檔案上傳的進度顯示問題,css的特效被落下了。隻是因為之前做了檔案上傳,但是并沒有真的思考過這些上傳進度的問題。前幾天看到一個部落格,有感而發,覺得這個上傳進度的問題遲早是會被遇到的。在這裡簡單介紹一下一般的實作方法和思路,希望即将踩坑的夥伴,借助這個文章能脫坑更順利點。

必備工具:

html css java

為了偷懶這裡我就直接使用了Springboot架構做為基礎項目demo來使用.

基本架構搭建:

使用Bootstrap內建前端樣式,本來就不擅長樣式編寫,這裡展示的樣式大家就湊合看吧。編寫基本的上傳檔案編輯位置即可,這裡重在實作檔案分割的業務實作。

實作檔案分割的方式可以簡單分為兩種: ① 定塊分割 ② 定長分割

定塊分割:不管檔案的大小是多少,定義檔案分割的塊數是制定的。比如我在這個項目中就是用了這種分割方式,定義無論上傳的檔案大小是多少都将其分割成10塊。專業角度來看,這種分割方式還是過于粗糙并且存在很多問題的,但是因為這裡為了為展示如何進行檔案分割,是以優化分割算法問題可以根據業務問題進行動态變更。

定長分割:相對定塊分割來說,這種方式會稍微好點。根據上傳的檔案大小進行分割檔案數量,請求上傳接口的次數也根據檔案大小變化。

當然,似乎這些方法進行分割似乎都不是最好的,但是檔案分割放在用戶端是為了減少單個大檔案上傳導緻一個老鼠壞一鍋湯的意外情況。

檔案分割:

使用定塊分割檔案,簡單的代碼實作:

function sliceFiles(file, num) { var fileList = []; var singleSize = Math.ceil(file.size / num); var location = 0; while (location < file.size) { fileList.push(file.slice(location, location + singleSize)); location += singleSize; } return fileList; }

經擷取到的檔案進行上傳,需要後端提供檔案上傳借口,這裡檔案上傳使用FormData的方式。接收檔案上傳的接口定位為:

如何實作檔案分片上傳[顯示檔案上傳進度]

檔案分片上傳的目的是為了實作檔案更加迅速的上傳,是以我們如果每次對檔案進行分割操作之後,在多次循環調用上傳檔案接口和單獨上傳相比沒有任何意義。是以我們這裡吧上傳檔案的方式設定成異步方法,等待檔案分片結束之後同時執行調用方法。

function uploadFileSingle(index, file) { return new Promise(function (resolve, reject) { console.log("content--------", index); var formData = new FormData(); formData.append("file", file); formData.append("index", index); $.ajax({ url: '/file/uploadSingle?_t=' + new Date().getMilliseconds(), type: "POST", processData: false, contentType: false, mimeType: "multipart/form-data", data: formData, success: function (data) { resolve.apply(data); }, error: function (data) { reject.apply(data); }, }); }) }

具體調用時:

如何實作檔案分片上傳[顯示檔案上傳進度]

代碼中提及到的mergeFile方法是為了将分片上傳的檔案進行合并,因為分片隻是目的,合并是為了将上傳到的檔案能夠保持原本的狀态。

合并檔案的思路:

說道了檔案分塊上傳,就不得不說檔案如何合并最終的檔案的思路。一個檔案還是需要有一個執行的辨別,友善最後的收集。分片的檔案需要有一定的順序性的辨別,比如 0,1,2之類的數字或者其他資訊辨別這個檔案是屬于整個檔案分割後的第幾塊檔案。我這裡隻是為了示範項目效果,我在分割之後隻是單純給他們定義了檔案的名字為:0 1 2 3 4 5 6 7 8 9。

是以我最後在合并檔案的時候按照數字順序拿到檔案,然後進行合并檔案操作即可。

對比效果:

關于這麼分片做的好處實際上有很多,我這邊做了一執行時間的簡單對比。備注:小檔案似乎在這裡不占優勢,是以這裡上傳的檔案的大小為:2.42GB

如何實作檔案分片上傳[顯示檔案上傳進度]

69.025

如何實作檔案分片上傳[顯示檔案上傳進度]

62.434

如果有興趣可以嘗試一下,除了我本地的寬帶等性能條件的限制,檔案稍微大點的時候會有速度上的提升。

檔案合并

檔案上傳結束之後需要主動請求資料進行合并,是以可以在Promise的then()方法中發起合并資料檔案的請求。

後端java代碼實作:

如何實作檔案分片上傳[顯示檔案上傳進度]

接下來我們可以在此基礎之上做點有意思的事情,優化上傳等待的互動,追加上傳進度的展示。

需要用到xhr,具體是的使用可以在ajax方法中擷取上傳的的進度資料:

如何實作檔案分片上傳[顯示檔案上傳進度]

xhr: function () { var xhr = new XMLHttpRequest(); xhr.upload.addEventListener('progress', function (e) { var progressRate = (e.loaded / e.total) * 100 + '%'; $(`#${index} div`).attr("style", `width: ${progressRate}`); }); return xhr; }

加上進度展示之後會大大優化普通loading等待導緻的互動弱勢感覺,看一下最終的效果:

如何實作檔案分片上傳[顯示檔案上傳進度]

微信公衆号:碼農的技術分享【更新速度有點慢 多多見諒】

源代碼請私信 檔案分片

知乎賬号:曦曦春風