Spring Boot 分片上傳、斷點(diǎn)續(xù)傳、大文件上傳、秒傳,建議收藏!

文件上傳是一個(gè)老生常談的話題了,在文件相對比較小的情況下,可以直接把文件轉(zhuǎn)化為字節(jié)流上傳到服務(wù)器,但在文件比較大的情況下,用普通的方式進(jìn)行上傳,這可不是一個(gè)好的辦法,畢竟很少有人會(huì)忍受,當(dāng)文件上傳到一半中斷后,繼續(xù)上傳卻只能重頭開始上傳,這種讓人不爽的體驗(yàn)。那有沒有比較好的上傳體驗(yàn)?zāi)?,答案有的,就是下邊要介紹的幾種上傳方式。

1、分片上傳

1.1 什么是分片上傳

分片上傳,就是將所要上傳的文件,按照一定的大小,將整個(gè)文件分隔成多個(gè)數(shù)據(jù)塊(我們稱之為Part)來進(jìn)行分別上傳,上傳完之后再由服務(wù)端對所有上傳的文件進(jìn)行匯總整合成原始的文件。

1.2 分片上傳的場景

大文件上傳

網(wǎng)絡(luò)環(huán)境環(huán)境不好,存在需要重傳風(fēng)險(xiǎn)的場景

2斷點(diǎn)續(xù)傳

2.1 什么是斷點(diǎn)續(xù)傳

斷點(diǎn)續(xù)傳是在下載或上傳時(shí),將下載或上傳任務(wù)(一個(gè)文件或一個(gè)壓縮包)人為的劃分為幾個(gè)部分,每一個(gè)部分采用一個(gè)線程進(jìn)行上傳或下載,如果碰到網(wǎng)絡(luò)故障,可以從已經(jīng)上傳或下載的部分開始繼續(xù)上傳或者下載未完成的部分,而沒有必要從頭開始上傳或者下載。

2.2 應(yīng)用場景

斷點(diǎn)續(xù)傳可以看成是分片上傳的一個(gè)衍生,因此可以使用分片上傳的場景,都可以使用斷點(diǎn)續(xù)傳。

2.3 實(shí)現(xiàn)斷點(diǎn)續(xù)傳的核心邏輯

在分片上傳的過程中,如果因?yàn)橄到y(tǒng)崩潰或者網(wǎng)絡(luò)中斷等異常因素導(dǎo)致上傳中斷,這時(shí)候客戶端需要記錄上傳的進(jìn)度。在之后支持再次上傳時(shí),可以繼續(xù)從上次上傳中斷的地方進(jìn)行繼續(xù)上傳。

為了避免客戶端在上傳之后的進(jìn)度數(shù)據(jù)被刪除而導(dǎo)致重新開始從頭上傳的問題,服務(wù)端也可以提供相應(yīng)的接口便于客戶端對已經(jīng)上傳的分片數(shù)據(jù)進(jìn)行查詢,從而使客戶端知道已經(jīng)上傳的分片數(shù)據(jù),從而從下一個(gè)分片數(shù)據(jù)開始繼續(xù)上傳。

整體的過程如下:

1、前端將文件安裝百分比進(jìn)行計(jì)算,每次上傳文件的百分之一(文件分片),給文件分片做上序號

2、后端將前端每次上傳的文件,放入到緩存目錄

3、等待前端將全部的文件內(nèi)容都上傳完畢后,發(fā)送一個(gè)合并請求

4、后端使用RandomAccessFile進(jìn)多線程讀取所有的分片文件,一個(gè)線程一個(gè)分片

5、后端每個(gè)線程按照序號將分片的文件寫入到目標(biāo)文件中

6、在上傳文件的過程中發(fā)生斷網(wǎng)了或者手動(dòng)暫停了,下次上傳的時(shí)候發(fā)送續(xù)傳請求,讓后端刪除最后一個(gè)分片

7、前端重新發(fā)送上次的文件分片

2.4 實(shí)現(xiàn)流程步驟

方案一,常規(guī)步驟

將需要上傳的文件按照一定的分割規(guī)則,分割成相同大小的數(shù)據(jù)塊;

初始化一個(gè)分片上傳任務(wù),返回本次分片上傳唯一標(biāo)識;

按照一定的策略(串行或并行)發(fā)送各個(gè)分片數(shù)據(jù)塊;

發(fā)送完成后,服務(wù)端根據(jù)判斷數(shù)據(jù)上傳是否完整,如果完整,則進(jìn)行數(shù)據(jù)塊合成得到原始文件。

方案二、本文實(shí)現(xiàn)的步驟

前端(客戶端)需要根據(jù)固定大小對文件進(jìn)行分片,請求后端(服務(wù)端)時(shí)要帶上分片序號和大小。

服務(wù)端創(chuàng)建conf文件用來記錄分塊位置,conf文件長度為總分片數(shù),每上傳一個(gè)分塊即向conf文件中寫入一個(gè)127,那么沒上傳的位置就是默認(rèn)的0,已上傳的就是Byte.MAX_VALUE 127(這步是實(shí)現(xiàn)斷點(diǎn)續(xù)傳和秒傳的核心步驟)

服務(wù)器按照請求數(shù)據(jù)中給的分片序號和每片分塊大小(分片大小是固定且一樣的)算出開始位置,與讀取到的文件片段數(shù)據(jù),寫入文件。

整體的實(shí)現(xiàn)流程如下:


3、分片上傳/斷點(diǎn)上傳代碼實(shí)現(xiàn)

3.1 前端實(shí)現(xiàn)

前端的File對象是特殊類型的Blob,且可以用在任意的Blob類型的上下文中。

就是說能夠處理Blob對象的方法也能處理File對象。在Blob的方法里有有一個(gè)Slice方法可以幫完成切片。

核心代碼:


當(dāng)然如果我們是vue項(xiàng)目的話還有更好的選擇,我們可以使用一些開源的框架,本文推薦使用vue-simple-uploader 實(shí)現(xiàn)文件分片上傳、斷點(diǎn)續(xù)傳及秒傳。

當(dāng)然我們也可以采用百度提供的webuploader的插件,進(jìn)行分片。操作方式也特別簡單,直接按照官方文檔給出的操作進(jìn)行即可。

3.2 后端寫入文件

后端用兩種方式實(shí)現(xiàn)文件寫入:

RandomAccessFile

MappedByteBuffer

在向下學(xué)習(xí)之前,我們先簡單了解一下這兩個(gè)類的使用

RandomAccessFile

Java除了File類之外,還提供了專門處理文件的類,即RandomAccessFile(隨機(jī)訪問文件)類。

該類是Java語言中功能最為豐富的文件訪問類,它提供了眾多的文件訪問方法。RandomAccessFile類支持“隨機(jī)訪問”方式,這里“隨機(jī)”是指可以跳轉(zhuǎn)到文件的任意位置處讀寫數(shù)據(jù)。在訪問一個(gè)文件的時(shí)候,不必把文件從頭讀到尾,而是希望像訪問一個(gè)數(shù)據(jù)庫一樣“隨心所欲”地訪問一個(gè)文件的某個(gè)部分,這時(shí)使用RandomAccessFile類就是最佳選擇。

RandomAccessFile對象類有個(gè)位置指示器,指向當(dāng)前讀寫處的位置,當(dāng)前讀寫n個(gè)字節(jié)后,文件指示器將指向這n個(gè)字節(jié)后面的下一個(gè)字節(jié)處。

剛打開文件時(shí),文件指示器指向文件的開頭處,可以移動(dòng)文件指示器到新的位置,隨后的讀寫操作將從新的位置開始。

RandomAccessFile類在數(shù)據(jù)等長記錄格式文件的隨機(jī)(相對順序而言)讀取時(shí)有很大的優(yōu)勢,但該類僅限于操作文件,不能訪問其他的I/O設(shè)備,如網(wǎng)絡(luò)、內(nèi)存映像等。

RandomAccessFile類的構(gòu)造方法如下所示:

這兩個(gè)構(gòu)造方法均涉及到一個(gè)String類型的參數(shù)mode,它決定隨機(jī)存儲(chǔ)文件流的操作模式,其中mode值及對應(yīng)的含義如下:

“r”:以只讀的方式打開,調(diào)用該對象的任何write(寫)方法都會(huì)導(dǎo)致IOException異常

“rw”:以讀、寫方式打開,支持文件的讀取或?qū)懭?。若文件不存在,則創(chuàng)建之。

“rws”:以讀、寫方式打開,與“rw”不同的是,還要對文件內(nèi)容的每次更新都同步更新到潛在的存儲(chǔ)設(shè)備中去。這里的“s”表示synchronous(同步)的意思

“rwd”:以讀、寫方式打開,與“rw”不同的是,還要對文件內(nèi)容的每次更新都同步更新到潛在的存儲(chǔ)設(shè)備中去。使用“rwd”模式僅要求將文件的內(nèi)容更新到存儲(chǔ)設(shè)備中,而使用“rws”模式除了更新文件的內(nèi)容,還要更新文件的元數(shù)據(jù)(metadata),因此至少要求1次低級別的I/O操作




MappedByteBuffer

java io操作中通常采用BufferedReader,BufferedInputStream等帶緩沖的IO類處理大文件,不過java nio中引入了一種基于MappedByteBuffer操作大文件的方式,其讀寫性能極高。

3.3 進(jìn)行寫入操作的核心代碼

為了節(jié)約文章篇幅,下面我只展示核心代碼。

RandomAccessFile實(shí)現(xiàn)方式


MappedByteBuffer實(shí)現(xiàn)方式

文件操作核心模板類代碼


上傳接口


4、秒傳

4.1 什么是秒傳

通俗的說,你把要上傳的東西上傳,服務(wù)器會(huì)先做MD5校驗(yàn),如果服務(wù)器上有一樣的東西,它就直接給你個(gè)新地址,其實(shí)你下載的都是服務(wù)器上的同一個(gè)文件,想要不秒傳,其實(shí)只要讓MD5改變,就是對文件本身做一下修改(改名字不行),例如一個(gè)文本文件,你多加幾個(gè)字,MD5就變了,就不會(huì)秒傳了。

4.2 實(shí)現(xiàn)的秒傳核心邏輯

利用redis的set方法存放文件上傳狀態(tài),其中key為文件上傳的md5,value為是否上傳完成的標(biāo)志位,當(dāng)標(biāo)志位true為上傳已經(jīng)完成,此時(shí)如果有相同文件上傳,則進(jìn)入秒傳邏輯。

如果標(biāo)志位為false,則說明還沒上傳完成,此時(shí)需要在調(diào)用set的方法,保存塊號文件記錄的路徑,其中,key為上傳文件md5加一個(gè)固定前綴,value為塊號文件記錄路徑


4.3 核心代碼

5、總結(jié)

在實(shí)現(xiàn)分片上傳的過程,需要前端和后端配合,比如前后端的上傳塊號的文件大小,前后端必須得要一致,否則上傳就會(huì)有問題。

其次文件相關(guān)操作正常都是要搭建一個(gè)文件服務(wù)器的,比如使用fastdfs、hdfs等。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容