1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        文件切片,斷點續(xù)傳-解決上傳大文件的問題

        共 3687字,需瀏覽 8分鐘

         ·

        2021-01-15 15:38


        點擊上方?藍字?關(guān)注我們!



        Java,Python,C/C++,Linux,PHP,Go,C#,QT,大數(shù)據(jù),算法,軟件教程,前端,簡歷,畢業(yè)設(shè)計等分類,資源在不斷更新中... 點擊領(lǐng)取!

        最近遇見一個需要上傳超大大文件的需求,調(diào)研了七牛和騰訊云的切片分段上傳功能,因此在此整理前端大文件上傳相關(guān)功能的實現(xiàn)。

        在某些業(yè)務(wù)中,大文件上傳是一個比較重要的交互場景,如上傳入庫比較大的Excel表格數(shù)據(jù)、上傳影音文件等。如果文件體積比較大,或者網(wǎng)絡(luò)條件不好時,上傳的時間會比較長(要傳輸更多的報文,丟包重傳的概率也更大),用戶不能刷新頁面,只能耐心等待請求完成。


        下面從文件上傳方式入手,整理大文件上傳的思路,并給出了相關(guān)實例代碼,由于PHP內(nèi)置了比較方便的文件拆分和拼接方法,因此服務(wù)端代碼使用PHP進行示例編寫。
        本文相關(guān)示例代碼位于github上,主要參考
        聊聊大文件上傳
        大文件切割上傳
        文件上傳的幾種方式
        首先我們來看看文件上傳的幾種方式。

        普通表單上傳
        使用PHP來展示常規(guī)的表單上傳是一個不錯的選擇。首先構(gòu)建文件上傳的表單,并指定表單的提交內(nèi)容類型為enctype="multipart/form-data",表明表單需要上傳二進制數(shù)據(jù)。

        然后編寫index.php上傳文件接收代碼,使用move_uploaded_file方法即可(php大法好…)

        form表單上傳大文件時,很容易遇見服務(wù)器超時的問題。通過xhr,前端也可以進行異步上傳文件的操作,一般由兩個思路。


        文件編碼上傳

        第一個思路是將文件進行編碼,然后在服務(wù)端進行解碼,之前寫過一篇在前端實現(xiàn)圖片壓縮上傳的博客,其主要實現(xiàn)原理就是將圖片轉(zhuǎn)換成base64進行傳遞

        varimgURL?=?URL.createObjectURL(file);

        ctx.drawImage(imgURL,?0,?0);

        //?獲取圖片的編碼,然后將圖片當(dāng)做是一個很長的字符串進行傳遞

        vardata=?canvas.toDataURL(?"image/jpeg",?0.5);

        在服務(wù)端需要做的事情也比較簡單,首先解碼base64,然后保存圖片即可

        $imgData?=?$_REQUEST[?'imgData'];

        $base64?=?explode(?',',?$imgData)[?1];

        $img?=?base64_decode($base64);

        $url?=?'./test.jpg';

        if(file_put_contents($url,?$img))?{
        exit(json_encode(?array(

        url?=>?$url

        )));

        }


        base64編碼的缺點在于其體積比原圖片更大(因為Base64將三個字節(jié)轉(zhuǎn)化成四個字節(jié),因此編碼后的文本,會比原文本大出三分之一左右),對于體積很大的文件來說,上傳和解析的時間會明顯增加。
        更多關(guān)于base64的知識,可以參考Base64筆記。
        除了進行base64編碼,還可以在前端直接讀取文件內(nèi)容后以二進制格式上傳
        //?讀取二進制文件

        functionreadBinary(text){
        vardata?=?newArrayBuffer(text.length);

        varui8a?=?newUint8Array(data,?0);

        for(?vari?=?0;?i?ui8a[i]?=?(text.charCodeAt(i)?&?0xff);

        }

        console.log(ui8a)

        }

        varreader?=?newFileReader;

        reader.?=?function{
        readBinary(?this.result)?//?讀取result或直接上傳

        }

        //?把從input里讀取的文件內(nèi)容,放到fileReader的result字段里

        reader.readAsBinaryString(file);

        formData異步上傳

        FormData對象主要用來組裝一組用 發(fā)送請求的鍵/值對,可以更加靈活地發(fā)送Ajax請求。可以使用FormData來模擬表單提交。
        letfiles?=?e.target.files?//?獲取input的file對象

        letformData?=?newFormData;

        formData.append(?'file',?file);

        axios.post(url,?formData);

        服務(wù)端處理方式與直接form表單請求基本相同。

        iframe無刷新頁面

        在低版本的瀏覽器(如IE)上,xhr是不支持直接上傳formdata的,因此只能用form來上傳文件,而form提交本身會進行頁面跳轉(zhuǎn),這是因為form表單的target屬性導(dǎo)致的,其取值有

        _self,默認值,在相同的窗口中打開響應(yīng)頁面

        _blank,在新窗口打開

        _parent,在父窗口打開

        _top,在最頂層的窗口打開

        framename,在指定名字的iframe中打開

        如果需要讓用戶體驗異步上傳文件的感覺,可以通過framename指定iframe來實現(xiàn)。把form的target屬性設(shè)置為一個看不見的iframe,那么返回的數(shù)據(jù)就會被這個iframe接受,因此只有該iframe會被刷新,至于返回結(jié)果,也可以通過解析這個iframe內(nèi)的文本來獲取。


        functionupload{
        varnow?=?+?newDate

        varid?=?'frame'+?now

        $(?"body").append(?`"display:none;"?name="${id}"?id="${id}"?/>`);

        var$form?=?$(?"#myForm")

        $form.attr({
        "action":?'/index.php',

        "method":?"post",

        "enctype":?"multipart/form-data",

        "encoding":?"multipart/form-data",

        "target":?id

        }).submit

        $(?"#"+id).on(?"load",?function{
        varcontent?=?$(?this).contents.find(?"body").text

        try{
        vardata?=?JSON.parse(content)

        }?catch(e){
        console.log(e)

        }

        })

        }


        大文件上傳

        現(xiàn)在來看看在上面提到的幾種上傳方式中實現(xiàn)大文件上傳會遇見的超時問題,
        表單上傳和iframe無刷新頁面上傳,實際上都是通過form標(biāo)簽進行上傳文件,這種方式將整個請求完全交給瀏覽器處理,當(dāng)上傳大文件時,可能會遇見請求超時的情形
        通過fromData,其實際也是在xhr中封裝一組請求參數(shù),用來模擬表單請求,無法避免大文件上傳超時的問題
        編碼上傳,我們可以比較靈活地控制上傳的內(nèi)容
        大文件上傳最主要的問題就在于:在同一個請求中,要上傳大量的數(shù)據(jù),導(dǎo)致整個過程會比較漫長,且失敗后需要重頭開始上傳。試想,如果我們將這個請求拆分成多個請求,每個請求的時間就會縮短,且如果某個請求失敗,只需要重新發(fā)送這一次請求即可,無需從頭開始,這樣是否可以解決大文件上傳的問題呢?

        綜合上面的問題,看來大文件上傳需要實現(xiàn)下面幾個需求
        支持拆分上傳請求(即切片)
        支持?jǐn)帱c續(xù)傳
        支持顯示上傳進度和暫停上傳
        接下來讓我們依次實現(xiàn)這些功能,看起來最主要的功能應(yīng)該就是切片了。

        文件切片
        參考:大文件切割上傳
        編碼方式上傳中,在前端我們只要先獲取文件的二進制內(nèi)容,然后對其內(nèi)容進行拆分,最后將每個切片上傳到服務(wù)端即可。
        在Java中,文件FIle對象是Blob對象的子類,Blob對象包含一個重要的方法slice,通過這個方法,我們就可以對二進制文件進行拆分。
        下面是一個拆分文件的示例,對于up6來說開發(fā)者不需要關(guān)心拆分的細節(jié),由控件幫助實現(xiàn),開發(fā)者只需要關(guān)心業(yè)務(wù)邏輯即可。
        控件上傳的時候會為每一個文件塊數(shù)據(jù)添加相關(guān)的信息,開發(fā)者在服務(wù)端接收到數(shù)據(jù)后可以自已進行處理。
        服務(wù)器接收到這些切片后,再將他們拼接起來就可以了,下面是PHP拼接切片的示例代碼
        對于up6來說,開發(fā)人員不需要進行拼接,up6已經(jīng)提供了示例代碼,已經(jīng)實現(xiàn)了這個邏輯。
        保證唯一性,控件會為每一個文件塊添加信息,如塊索引,塊MD5,文件MD5

        斷點續(xù)傳
        up6自帶續(xù)傳功能,up6在服務(wù)端已經(jīng)保存了文件的信息,在客戶端也保存了文件的進度信息。在上傳時控件會自動加載文件進度信息,開發(fā)者不需要關(guān)心這些細節(jié)。在文件塊的處理邏輯中只需要根據(jù)文件塊索引來識別即可。
        此時上傳時刷新頁面或者關(guān)閉瀏覽器,再次上傳相同文件時,之前已經(jīng)上傳成功的切片就不會再重新上傳了。
        服務(wù)端實現(xiàn)斷點續(xù)傳的邏輯基本相似,只要在getUploadSliceRecord內(nèi)部調(diào)用服務(wù)端的查詢接口獲取已上傳切片的記錄即可,因此這里不再展開。
        此外斷點續(xù)傳還需要考慮切片過期的情況:如果調(diào)用了mkfile接口,則磁盤上的切片內(nèi)容就可以清除掉了,如果客戶端一直不調(diào)用mkfile的接口,放任這些切片一直保存在磁盤顯然是不可靠的,一般情況下,切片上傳都有一段時間的有效期,超過該有效期,就會被清除掉?;谏鲜鲈?,斷點續(xù)傳也必須同步切片過期的實現(xiàn)邏輯。

        續(xù)傳效果

        上傳進度和暫停
        通過xhr.upload中的progress方法可以實現(xiàn)監(jiān)控每一個切片上傳進度。
        上傳暫停的實現(xiàn)也比較簡單,通過xhr.abort可以取消當(dāng)前未完成上傳切片的上傳,實現(xiàn)上傳暫停的效果,恢復(fù)上傳就跟斷點續(xù)傳類似,先獲取已上傳的切片列表,然后重新發(fā)送未上傳的切片。
        由于篇幅關(guān)系,上傳進度和暫停的功能這里就先不實現(xiàn)了。
        實現(xiàn)效果:
        ?

        小結(jié)
        目前社區(qū)已經(jīng)存在一些成熟的大文件上傳解決方案,如七牛SDK,騰訊云SDK等,也許并不需要我們手動去實現(xiàn)一個簡陋的大文件上傳庫,但是了解其原理還是十分有必要的。
        本文首先整理了前端文件上傳的幾種方式,然后討論了大文件上傳的幾種場景,以及大文件上傳需要實現(xiàn)的幾個功能
        通過Blob對象的slice方法將文件拆分成切片
        整理了服務(wù)端還原文件所需條件和參數(shù),演示了PHP將切片還原成文件
        通過保存已上傳切片的記錄來實現(xiàn)斷點續(xù)傳
        還留下了一些問題,如:合并文件時避免內(nèi)存溢出、切片失效策略、上傳進度暫停等功能,并沒有去深入或一一實現(xiàn),繼續(xù)學(xué)習(xí)吧


        往期推薦

        程序員的四個等級:菜鳥、普通、大牛、大神

        Spring AOP 設(shè)計思想與原理(圖文并茂)

        7 款神秘的開源項目!

        大文件上傳的幾種優(yōu)化思路

        END



        若覺得文章對你有幫助,隨手轉(zhuǎn)發(fā)分享,也是我們繼續(xù)更新的動力。


        長按二維碼,掃掃關(guān)注哦

        ?「C語言中文網(wǎng)」官方公眾號,關(guān)注手機閱讀教程??


        必備編程學(xué)習(xí)資料


        目前收集的資料包括:?Java,Python,C/C++,Linux,PHP,go,C#,QT,git/svn,人工智能,大數(shù)據(jù),單片機,算法,小程序,易語言,安卓,ios,PPT,軟件教程,前端,軟件測試,簡歷,畢業(yè)設(shè)計,公開課?等分類,資源在不斷更新中...


        點擊“閱讀原文”,立即免費領(lǐng)取最新資料!
        ??????
        瀏覽 154
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            91丨PORNY丨成人国产 | 中文字幕之久久 | 啊轻点都日出白浆了 | 夜夜av | 亚洲国产欧美日韩在线 | 亚洲AV成人精品毛片 | 熟妇丰满多毛的大隂户仙踪林 | 99riav3国产精品视频 | 苍井空一级婬片A片AⅤ网站 | 韩国三级老头和少妇 |