兄弟們看到這個標題可能會覺得是個標題黨,為了解決疑慮,我們先來看下最終的測試結果:
測試雲盤下載的文件 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