Spring Boot 分片上傳、斷點(diǎn)續(xù)傳佩抹、大文件上傳叼风、秒傳取董,建議收藏棍苹!

文件上傳是一個(gè)老生常談的話題了,在文件相對(duì)比較小的情況下茵汰,可以直接把文件轉(zhuǎn)化為字節(jié)流上傳到服務(wù)器枢里,但在文件比較大的情況下,用普通的方式進(jìn)行上傳蹂午,這可不是一個(gè)好的辦法栏豺,畢竟很少有人會(huì)忍受,當(dāng)文件上傳到一半中斷后豆胸,繼續(xù)上傳卻只能重頭開(kāi)始上傳奥洼,這種讓人不爽的體驗(yàn)。那有沒(méi)有比較好的上傳體驗(yàn)?zāi)赝砗鸢赣械牧榻保褪窍逻呉榻B的幾種上傳方式。

1估盘、分片上傳

1.1 什么是分片上傳

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

1.2 分片上傳的場(chǎng)景

大文件上傳

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

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)上傳或下載的部分開(kāi)始繼續(xù)上傳或者下載未完成的部分故河,而沒(méi)有必要從頭開(kāi)始上傳或者下載。

2.2 應(yīng)用場(chǎng)景

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

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

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

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

整體的過(guò)程如下:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

前端(客戶端)需要根據(jù)固定大小對(duì)文件進(jìn)行分片咧虎,請(qǐng)求后端(服務(wù)端)時(shí)要帶上分片序號(hào)和大小卓缰。

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

服務(wù)器按照請(qǐng)求數(shù)據(jù)中給的分片序號(hào)和每片分塊大邪葡浴(分片大小是固定且一樣的)算出開(kāi)始位置,與讀取到的文件片段數(shù)據(jù)总寒,寫(xiě)入文件扶歪。

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


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

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

前端的File對(duì)象是特殊類型的Blob摄闸,且可以用在任意的Blob類型的上下文中善镰。

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

核心代碼:


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

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

3.2 后端寫(xiě)入文件

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

RandomAccessFile

MappedByteBuffer

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

RandomAccessFile

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

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

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

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

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

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

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

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

“rw”:以讀串前、寫(xiě)方式打開(kāi),支持文件的讀取或?qū)懭胧当巍H粑募淮嬖诶疑耄瑒t創(chuàng)建之。

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

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




MappedByteBuffer

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

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

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

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


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

文件操作核心模板類代碼


上傳接口


4、秒傳

4.1 什么是秒傳

通俗的說(shuō)烹吵,你把要上傳的東西上傳碉熄,服務(wù)器會(huì)先做MD5校驗(yàn),如果服務(wù)器上有一樣的東西肋拔,它就直接給你個(gè)新地址锈津,其實(shí)你下載的都是服務(wù)器上的同一個(gè)文件,想要不秒傳凉蜂,其實(shí)只要讓MD5改變琼梆,就是對(duì)文件本身做一下修改(改名字不行)七咧,例如一個(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曾棕,則說(shuō)明還沒(méi)上傳完成扣猫,此時(shí)需要在調(diào)用set的方法,保存塊號(hào)文件記錄的路徑翘地,其中申尤,key為上傳文件md5加一個(gè)固定前綴,value為塊號(hào)文件記錄路徑


4.3 核心代碼

5衙耕、總結(jié)

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

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末和簸,一起剝皮案震驚了整個(gè)濱河市彭雾,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌比搭,老刑警劉巖冠跷,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異身诺,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)抄囚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門霉赡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人幔托,你說(shuō)我怎么就攤上這事穴亏》渑玻” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵嗓化,是天一觀的道長(zhǎng)棠涮。 經(jīng)常有香客問(wèn)我,道長(zhǎng)刺覆,這世上最難降的妖魔是什么严肪? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮谦屑,結(jié)果婚禮上驳糯,老公的妹妹穿的比我還像新娘。我一直安慰自己氢橙,他們只是感情好酝枢,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著悍手,像睡著了一般帘睦。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上坦康,一...
    開(kāi)封第一講書(shū)人閱讀 51,292評(píng)論 1 301
  • 那天官脓,我揣著相機(jī)與錄音,去河邊找鬼涝焙。 笑死卑笨,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的仑撞。 我是一名探鬼主播赤兴,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼隧哮!你這毒婦竟也來(lái)了桶良?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤沮翔,失蹤者是張志新(化名)和其女友劉穎陨帆,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體采蚀,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡疲牵,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了榆鼠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纲爸。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖妆够,靈堂內(nèi)的尸體忽然破棺而出识啦,到底是詐尸還是另有隱情负蚊,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布颓哮,位于F島的核電站家妆,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏冕茅。R本人自食惡果不足惜伤极,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望嵌赠。 院中可真熱鬧塑荒,春花似錦、人聲如沸姜挺。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)炊豪。三九已至凌箕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間词渤,已是汗流浹背牵舱。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留缺虐,地道東北人芜壁。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像高氮,于是被迫代替她去往敵國(guó)和親慧妄。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容