Java實現大文件下載,提速30倍!想學?我教你啊!

2021-02-14 我是程序汪
前言

兄弟們看到這個標題可能會覺得是個標題黨,為了解決疑慮,我們先來看下最終的測試結果:

測試雲盤下載的文件 46M,自己本地最大下載速度 2M

1. 單線程下載,總耗時: 603simg2. 多線程下載,50個線程,總耗時:13simg

測試結果,提速46倍,我還是太謙虛了,只說提速30倍,此處我們覺得應該有掌聲(我聽不到,還是點讚實在)

HTTP協議Range請求頭

Range主要是針對只需要獲取部分資源的範圍請求,通過指定Range即可告知伺服器資源的指定範圍。格式: Range: bytes=start-end

比如:獲取字節範圍 5001-10000

Range: bytes=5001-10000
1

也可以指定開始位置不指定結束位置,表示獲取開始位置之後的全部數據

Range: bytes=5001-
1

伺服器接收到帶有Range的請求,會在處理請求之後返回狀態碼為206 Partial Content的響應。

基於Range的特性,我們就可以實現文件的多線程下載,文件的斷點續傳

準備工作

本文我們使用的SpringMVC中的RestTemplate;由於雲盤的連結是Https,所以我們需要設置RestTemplate繞過證書驗證

編寫RestTemplate的構造器,以及繞過https的證書驗證在下載的過程中,我們需要知道當前下載的速度是多少,所以需要定義一個顯示下載速度的接口

因為計算下載速度,我們需要知道每秒傳輸的字節數是多少,為了監控傳輸數據的過程,我們需要了解SpringMVC中的接口ResponseExtractor

該接口只有一個方法,當客戶端和伺服器端連接建立之後,會調用這個方法,我們可以在這個方法中監控下載的速度。

DisplayDownloadSpeed接口的抽象實現 AbstractDisplayDownloadSpeedResponseExtractor簡單的文件下載器

這裡使用的是restTemplate調用execute, 先文件獲取到字節數組, 再將字節數組直接寫到目標文件。

這裡我們需要注意的點是: 這種方式會將文件的字節數組全部放入內存中, 及其消耗資源;我們來看看如何實現。

創建ByteArrayResponseExtractor類繼承AbstractDisplayDownloadSpeedResponseExtractor調用restTemplate.execute執行下載,保存字節數據到文件中

執行一段時間之後,我們可以看到內存已經使用了800M左右,所以這種方式只能使用於小文件的下載,如果我們下載幾G的大文件,內存肯定是不夠用的。至於下載時間,因為文件太大也沒有等下載完成就結束了程序。

單線程大文件下載

上面的方式只能下載小的文件,那大文件的下載我們該用什麼方式呢?我們可以把流輸出到文件而不是內存中。接下來我們來實現我們大文件的下載。

創建FileResponseExtractor類繼承AbstractDisplayDownloadSpeedResponseExtractor,把流輸出到文件中文件下載器,先把流輸出到臨時下載文件(xxxxx.download),下載完成後在重命名文件

執行一段時間之後,我們再看看下內存的使用情況,發現這種方式內存消耗較少,效果比較理想,下載時間:199s

多線程文件下載

如果伺服器不限速的話,通常能夠把自己本地的帶寬給跑滿,那麼使用單線程下載就夠了,但是如果遇到伺服器限速,下載速度遠小於自己本地的帶寬,那麼可以考慮使用多線程下載。多線程我們使用CompletableFuture(可以參考文章 CompletableFuture讓你的代碼免受阻塞之苦)。

實現多線程文件下載的基本流程:

首先我們通過Http協議的Head方法獲取到文件的總大小然後根據設置的線程數均分文件的大小,計算每個線程的下載的字節數據開始位置和結束位置開啟線程,設置HTTP請求頭Range信息,開始下載數據到臨時文件下載完成後把每個線程下載完成的臨時文件合併成一個文件

完成代碼如下:

img

從執行的結果上來看,因為開啟了30個線程同時在下載,內存的佔用要比單線程消耗的多,但是也在接受範圍內,下載時間:81s,速度提升2.5倍,這是因為idea的下載伺服器沒有限速,本次多線程速度的提升僅僅是在充分的壓榨本地的帶寬,所以提示的幅度不大。

單線程下載和對線程下載對比測試

因為雲盤對單個線程的下載速度做了限制,大概是在100kb,所以我們使用雲盤的下載連結,來測試多線程和單線程的下載速度。

測試 雲盤中 46M 的文件的下載速度,自己本地最大下載速度 2M

注意:從瀏覽器中獲取的連結需要先使用URLDecode解碼,否則下載會失敗,並且雲盤文件的下載連結是有時效性的,過期後就不能在下載,需要重新生成下載連結

」測試單線程下載文件

執行的結果可以看出,雲盤對單線程的下載限速真的是喪心病狂, 46M的文件下載需要耗時:600s

測試多線程下載文件

為了充分的壓榨網速,找出最合適的線程數,所以測試了不同線程數的下載速度

線程數下載總耗時1060s2030s3021s4015s5013s

從測試的結果上來看,對於自己的運行環境把線程數設置在30個左右比較合適

文件斷點續傳如何實現,歡迎在大家評論區說出自己的思路。

源碼地址:https://gitee.com/silently9527/fast-download

相關焦點

  • JAVA實現大文件多線程下載,提速30倍!想學?我教你啊
    測試結果,「提速46倍」,我還是太謙虛了,只說提速30倍,此處我們覺得應該有掌聲(我聽不到,還是點讚實在)至於下載時間,因為文件太大也沒有等下載完成就結束了程序。單線程大文件下載上面的方式只能下載小的文件,那大文件的下載我們該用什麼方式呢?我們可以把流輸出到文件而不是內存中。接下來我們來實現我們大文件的下載。
  • 基於Spring Boot 2.2.6實現Rest風格的文件上傳&下載APIs-附源碼
    Spring Boot 2.0 Restful Style MultipartFile Upload and Download APIs文件上傳與下載在Web應用中是一個比較常見的功能。在本教程中,我將基於Spring 2.2.6版本實現一個基於Restful風格的文件上傳與下載APIs。
  • 如果你想學C語言,下載哪個編譯器好?
    C語言這個東西現在用的人很少,一般都是用java的多,不過對於我來講,我一看C語言就親切,就想寫,工作上不一定能用得到,但是C語言作為作為所有高級語言的爸爸,多學一點有助於理解一些底層的東西,下面我就跟大家說一下想學C語言下載哪個編譯器好。
  • 讓win7電腦提速50倍的方法!
    今天大神終於教小編一篇win7電腦提速50倍的方法,小編懷著好奇心嘗試了一下,卻發現真的太好用了!現在小編的電腦飛速運轉,好像回到了一年前嶄新的時刻!現在IT視窗小編就將win7電腦提速50倍的方法分享出來!!!
  • 百度網盤PC版新增 「下載提速」:非會員免費 下載速度平均提升3.2倍
    不想買會員,有沒有提升下載速度的辦法呢?近日,百度網盤新增了一項「下載提速」功能,可利用閒置帶寬為下載加速或換去積分。在最新版的百度網盤PC版中,百度增加了一項名為「下載提速」的功能。點擊「設置」——「傳輸」即可找到。
  • Java反射機制,速度提高1000倍
    以下為譯文:幾個星期前,我想讓我的代碼運行快1000倍,同時不改變複雜度,正如標題所說的,使用Java反射機制,可以讓代碼運行得更快。首先來解釋一下為什麼會首先使用反射機制。我有一個接口(表示一個樹節點)和一個實現這個接口的大量類(100+)。訣竅在於,樹是異構的,每個節點類型可以有不同數量的子節點,或者以不同的方式存儲它們。
  • 百度網盤下載提速,使用下載腳本!
    而不久前,小嘟下載網盤文件的時候,發現速度快了很多,難道百度網盤不限速了?並不是,而是官方對於免費用戶,推出了一種「提速模式」,就是將以前的「用戶激勵計劃」,變成了「提速模式」。所有文件都能提速嗎?也並不是,只有熱門資源,下載速度才會提高,而且速度也不太穩定;而像一些私人大文件,下載速度還是龜速,這點與迅雷類似。但總的來說,還是比以前要好一點點。對於小夥伴的私人小視頻,如何下載提速呢?小嘟之前也分享了一些第三方下載器,有興趣的小夥伴可以看看以前的文章。今天小嘟,給大家分享兩個新方法。
  • 這是逼我開會員啊……
    啊勒?下載終於不限速了嗎?nonono!百度網盤官方之前也澄清過了。限速的原因是運營維護成本太高了!開啟方法有點麻煩,但小雷還是會手把手教你們的。在網盤下載文件,一般都會有個「體驗極速下載」按鈕,在咱們享受完60秒免費提速後。才會彈出一個「延長加速時間」的提示。當你點擊提示後,會問你要不要購買。
  • Java Web安全 || Java基礎 · Java IO/NIO多種讀寫文件方式
    點擊上方「凌天實驗室」,「星標或置頂公眾號」漏洞、技術還是其他,我都想第一時間和你分享【歷史】已連載更新全部內容
  • java大數據之Hadoop開發環境
    JAVA和大數據是什麼關係大數據框架的編寫支持很多開發語言,但是Java在大數據開發方面有很大的優勢,目前流行的大數據Hadoop
  • Java中如何高效的讀取大文件
    在java編程中, 我想大部分小夥伴都在使用BufferReader,那麼是否有更高效的讀取方式呢?
  • 無需會員,就能享受下載提速!
    可是,最近,百度網盤突然推出了一個新功能:無需會員,就可以享受下載提速!你猜我信不信?我下載同一個內容,測試了一下!或許,下載速度與文件大小、個人運氣有關係吧!不過,我建議不開啟,或者是你在下載的時候開啟,平時關閉。
  • 老杜帶你學Java【第十課】
    上期連結:老杜帶你學Java【第九課】今後,我們就是Java軟體工程師了。
  • 跟我學java編程—Java的switch結構
    在D盤Java目錄下,新建「CaseSample.java」文件。用記事本打開「CaseSample.java」文件,輸入以下代碼:代碼結構分析程序功能主要是演示switch結構的使用。用戶輸入的學生分數存儲在score變量中,switch後面的表達式為score/10,將輸入的分數縮小10倍,其數值範圍約束在0到10之間,然後依次與case語句的常量表達式進行匹配,匹配成功的項,將與分數相對應的級別賦值給字符串類型grade,執行break語句跳出switch結構。如果沒有匹配項,則執行default語句,將flag變量設置為false。
  • Switch下載太慢,如何有效提速?——Switch加速下載聯機原理與實操方法
    CDN可以粗暴地可以理解為分布在全國各地,全世界各地的巨大硬碟,上面裝滿了遊戲文件、視頻、音樂和圖片等文件。如果你在上海,用電信的網絡在聽網易雲音樂,那麼你的歌曲就會優先加載存儲在上海電信的CDN上,這樣響應又快,速度又快。好,現在說到任天堂了。
  • Java國王:我來告訴你什麼才是真正的封裝!
    國王瞪了大臣甲一眼,訓斥道:「不要什麼都學Python!  我們也得有點獨特的東西啊。對於如何組織class, 我們可以用package,一個package對應文件系統的一個目錄,下面可以有多個class文件。 如果一個類沒有被public 修飾,那他只能被同一個package下面的類訪問,其他package的類是訪問不到的。這個設計不錯吧?!」 國王甚為得意。
  • Java文件操作——XML文件的讀取
    XML文件的表現:以「.xml」為文件擴展名的文件;存儲結構:樹形結構; 節點名稱區分大小寫。答案就是我們要學習的XML文件。我們可以使用相同的xml把不同的文件聯繫起來官方方式,不需要下載jar包DOM4J、JDOM :第三方,需要網上下載jar包示例:解析XML文件,目標是解析XML文件後,Java程序能夠得到xml文件的所有數據思考:如何在Java程序中保留xml數據的結構?
  • Java讀取和寫入txt文件
    1 問題描述對於java的讀取和寫入txt一直心存疑惑,隨著知識的積累,又重新進行學習,對java的文件讀寫理解更加深刻,在這裡將自己的小小經驗總結分享給大家。下面是大家了解java流的一個基本框架。而字符流的實現是基於自動轉換的,讀取數據時會把數據按照JVM的默認編碼自動轉換成字符。字符流是由Java虛擬機將字節轉化為2個字節的Unicode字符為單位的字符而成的。
  • 跟我學java編程—Java簡單條件結構
    在Java語言中,提供了if語句結構來實現條件結構。本節內容只介紹最簡單的條件語句:if語句。如果語句塊中有多個語句,則需要將它們用一對大括號「{}」括起來,表面在條件的值為真時,需要處理整個語句塊。在D盤Java目錄下,新建「ConditionSample1.java」文件。用記事本打開「ConditionSample1.java」文件,輸入以下代碼:代碼結構分析程序功能主要是演示if語句的使用。
  • 我是一個Java class
    "唉,果然沒有被裝載過, 你是個class 文件,當然要報文件開頭的那幾個數了, 就是Java 他爸James Gosling 在jdk 1.0時確定的那個數啊""奧, 我看看, 0xCAFEBABE""不錯, 是個java 類, 把你後邊的兩個數也報一下", 小個子繼續問"50 , 0" "看來版本不高啊, 是jdk 1.6編譯出來的啊