程式碼示例 | 斷點續傳(大文件的下載)後台功能實現

  • 2020 年 2 月 14 日
  • 筆記

點擊「碼上有猿」關注公眾號獲取最新資訊

版權聲明:版權所有,未經許可,不得轉載,轉載或者引用本文內容請註明來源及原作者

文章福利

掌握:思想、方法

收益:發現問題、分析問題、定位問題、解決問題

案例分析

某網盤

  • 可以隨時暫停、啟動
  • 多任務
  • 下載過程中、由於某一些特殊原因(宕機、斷電、斷網等),導致文件下載失敗
    • 再一次下載的時候,還可以繼續在原來的基礎上下載
    • 當上一次下載的20%,再一次下載的時候,從20%繼續下載
  • 本地都會產生一個臨時數據文件
    • 中斷後,文件不會消失

斷點續傳

原理:

實現:

長連接:socket、urlconnection、http、okhttp、httpclient

思路:

  • 指定URL
  • 建立一個目錄(指定臨時文件)
  • 從伺服器中獲取對象流
  • 告訴伺服器從哪個位置下標,開始發送數據
  • 將對象流對象,寫入到臨時文件中
  • 根據讀取到的對象流長度來進行定義
  • 如果長度有值,則進行寫入
  • 如果長度=-1,則無需進行寫入操作

程式碼:

/**   *   * @author: likang   * @date: 2019/12/5 20:44   * @description: 斷點續傳(仿百度網盤下載功能)   */  public class FileDownLoadUtils {        public static void main(String[] args) {          //指定URL          String url = "http://mirrors.aliyun.com/centos/8.0.1905/isos/x86_64/CentOS-8-x86_64-1905-dvd1.iso";          //下載文件          downLoadFile(url);      }        /*       * @Description: 創建文件       * @author: likang       * @date: 2019/12/5 20:47       * @params: [url]       * @return: void       * @exception:       */      private static void downLoadFile(String url) {          //指定本地下載的目錄地址          File file = new File(FileDownLoadUtils.class.getResource("").getFile());          //        //生成一個臨時文件(目的:主要是記錄數據的下標位置(位元組長度))          //        //getAbsolutePath:獲取絕對路徑          //        //separator:自動識別當前系統資源分割符合            file = new File(file.getAbsolutePath() + File.separator + "CentOS-8-x86_64-1905-dvd1.iso.bak");          //如果目錄不存在,則創建          if(!file.exists()){              try {                  file.createNewFile();              } catch (IOException e) {                  e.printStackTrace();              }          }          //將url中的數據流對象,寫入到臨時文件中file          writeFile(url,file);        }        /*       * @Description: 通過url獲取伺服器對象流,並寫入到文件中file       * @author: likang       * @date: 2019/12/5 21:00       * @params: [url, file]       * @return: void       * @exception:       */      private static void writeFile(String url, File file) {            byte[] bytes = new byte[1024*1024];          //定義流對象          InputStream inputStream = null;//數據流          FileOutputStream fileOutputStream = null;//寫入file對象數據流          long fileLength = 0;          int byteCount = 0;          //根據URL和伺服器建立連接---數據流          try {              fileOutputStream = new FileOutputStream(file, true);              fileLength = file.length();              //建立連接,獲取對象流              inputStream = getInputStream(url,fileLength);  //            byteCount = inputStream.read(bytes);  //            while(byteCount != -1){  //                //數據流---file文件中(臨時文件)  //                fileOutputStream.write(bytes, 0, byteCount);  //            }              while((byteCount = inputStream.read(bytes)) != -1){                  //數據流---file文件中(臨時文件)                  fileOutputStream.write(bytes, 0, byteCount);              }          } catch (Exception e) {              e.printStackTrace();          }finally {               //關閉流對象              try {                  inputStream.close();                  fileOutputStream.close();              } catch (IOException e) {                  e.printStackTrace();              }          }            }        /*       * @Description: 建立連接、獲取對象流       * @author: likang       * @date: 2019/12/5 21:18       * @params: [url, fileLength]       * @return: java.io.InputStream       * @exception:       */      private static InputStream getInputStream(String url, long startFileLength) {          InputStream inputStream = null;          HttpURLConnection connection;            try {              URL filePath = new URL(url);//和伺服器建立連接、獲取文件路徑              connection = (HttpURLConnection) filePath.openConnection();//開啟連接              connection.setConnectTimeout(3*1000);//連接超時時間              long lengthLong = connection.getContentLengthLong();//文件的總長度              if(startFileLength < lengthLong){//還沒下載完畢                  connection.disconnect();//銷毀鏈接                  connection = (HttpURLConnection) filePath.openConnection();//開啟連接                  connection.setConnectTimeout(3*1000);//連接超時時間                  connection.setRequestProperty("RANGE", "bytes=" + startFileLength + "-");//設置請求發送下標的對象                  System.out.println(connection.getContentLengthLong());                  inputStream = connection.getInputStream();              }          } catch (Exception e) {              e.printStackTrace();          }          return inputStream;        }    }  

HTTP擴展

Accept 設置接受的內容類型    Accept: text/plain    Accept-Charset 設置接受的字元編碼    Accept-Charset: utf-8    Accept-Encoding 設置接受的編碼格式    Accept-Encoding: gzip, deflate    Accept-Datetime 設置接受的版本時間    Accept-Datetime: Thu, 31 May 2007 20:35:00 GMT    Accept-Language 設置接受的語言    Accept-Language: en-US    Authorization 設置HTTP身份驗證的憑證    Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==    Cache-Control 設置請求響應鏈上所有的快取機制必須遵守的指令    Cache-Control: no-cache    Connection 設置當前連接和hop-by-hop協議請求欄位列表的控制選項    Connection: keep-alive  Connection: Upgrade    Content-Length 設置請求體的位元組長度    Content-Length: 348    Content-MD5 設置基於MD5演算法對請求體內容進行Base64二進位編碼    Content-MD5: Q2hlY2sgSW50ZWdyaXR5IQ==    Content-Type 設置請求體的MIME類型(適用POST和PUT請求)    Content-Type: application/x-www-form-urlencoded    Cookie 設置伺服器使用Set-Cookie發送的http cookie    Cookie: $Version=1; Skin=new;    Date 設置消息發送的日期和時間    Date: Tue, 15 Nov 1994 08:12:31 GMT    Expect 標識客戶端需要的特殊瀏覽器行為    Expect: 100-continue    Forwarded 披露客戶端通過http代理連接web服務的源資訊    Forwarded: for=192.0.2.60;proto=http;by=203.0.113.43  Forwarded: for=192.0.2.43, for=198.51.100.17    From 設置發送請求的用戶的email地址    From: [email protected]    Host 設置伺服器域名和TCP埠號,如果使用的是服務請求標準埠號,埠號可以省略    Host: en.wikipedia.org:8080  Host: en.wikipedia.org    If-Match 設置客戶端的ETag,當時客戶端ETag和伺服器生成的ETag一致才執行,適用於更新自從上次更新之後沒有改變的資源    If-Match: "737060cd8c284d8af7ad3082f209582d    If-Modified-Since 設置更新時間,從更新時間到服務端接受請求這段時間內如果資源沒有改變,允許服務端返回304 Not Modified    If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT    If-None-Match 設置客戶端ETag,如果和服務端接受請求生成的ETage相同,允許服務端返回304 Not Modified    If-None-Match: "737060cd8c284d8af7ad3082f209582d"    If-Range 設置客戶端ETag,如果和服務端接受請求生成的ETage相同,返回缺失的實體部分;否則返回整個新的實體    If-Range: "737060cd8c284d8af7ad3082f209582d"    If-Unmodified-Since 設置更新時間,只有從更新時間到服務端接受請求這段時間內實體沒有改變,服務端才會發送響應    If-Unmodified-Since: Sat, 29 Oct 1994 19:43:31 GMT    Max-Forwards 限制代理或網關轉發消息的次數    Max-Forwards: 10    Origin 標識跨域資源請求(請求服務端設置Access-Control-Allow-Origin響應欄位)    Origin: http://www.example-social-network.com    Pragma 設置特殊實現欄位,可能會對請求響應鏈有多種影響    Pragma: no-cache    Proxy-Authorization 為連接代理授權認證資訊    Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==    Range 請求部分實體,設置請求實體的位元組數範圍,具體可以參見HTTP/1.1中的Byte serving    Range: bytes=500-999    Referer 設置前一個頁面的地址,並且前一個頁面中的連接指向當前請求,意思就是如果當前請求是在A頁面中發送的,那麼referer就是A頁面的url地址(軼事:這個單詞正確的拼法應該是"referrer",但是在很多規範中都拼成了"referer",所以這個單詞也就成為標準用法)    Referer: http://en.wikipedia.org/wiki/Main_Page    TE 設置用戶代理期望接受的傳輸編碼格式,和響應頭中的Transfer-Encoding欄位一樣    TE: trailers, deflate    Upgrade 請求服務端升級協議    Upgrade: HTTP/2.0, HTTPS/1.3, IRC/6.9, RTA/x11, websocket    User-Agent 用戶代理的字元串值    User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:12.0) Gecko/20100101 Firefox/21.0    Via 通知伺服器代理請求    Via: 1.0 fred, 1.1 example.com (Apache/1.1)    Warning 實體可能會發生的問題的通用警告    Warning: 199 Miscellaneous warning    常用非標準請求頭欄位  X-Requested-With 標識Ajax請求,大部分js框架發送請求時都會設置它為XMLHttpRequest    X-Requested-With: XMLHttpRequest    DNT 請求web應用禁用用戶追蹤    DNT: 1 (Do Not Track Enabled)  DNT: 0 (Do Not Track Disabled)    X-Forwarded-For 一個事實標準,用來標識客戶端通過HTTP代理或者負載均衡器連接的web伺服器的原始IP地址    X-Forwarded-For: client1, proxy1, proxy2  X-Forwarded-For: 129.78.138.66, 129.78.64.103    X-Forwarded-Host 一個事實標準,用來標識客戶端在HTTP請求頭中請求的原始host,因為主機名或者反向代理的埠可能與處理請求的原始伺服器不同    X-Forwarded-Host: en.wikipedia.org:8080  X-Forwarded-Host: en.wikipedia.org    X-Forwarded-Proto 一個事實標準,用來標識HTTP原始協議,因為反向代理或者負載均衡器和web伺服器可能使用http,但是請求到反向代理使用的是https    X-Forwarded-Proto: https    Front-End-Https 微軟應用程式和負載均衡器使用的非標準header欄位 Front-End-Https: on  X-Http-Method-Override 請求web應用時,使用header欄位中給定的方法(通常是put或者delete)覆蓋請求中指定的方法(通常是post),如果用戶代理或者防火牆不支援直接使用put或者delete方法發送請求時,可以使用這個欄位    X-HTTP-Method-Override: DELETE    X-ATT-DeviceId 允許更簡單的解析用戶代理在AT&T設備上的MakeModel/Firmware    X-Att-Deviceid: GT-P7320/P7320XXLPG    X-Wap-Profile 設置描述當前連接設備的詳細資訊的xml文件在網路中的位置    x-wap-profile: http://wap.samsungmobile.com/uaprof/SGH-I777.xml    Proxy-Connection 早起HTTP版本中的一個誤稱,現在使用標準的connection欄位    Proxy-Connection: keep-alive    X-UIDH 服務端深度包檢測插入的一個唯一ID標識Verizon Wireless的客戶    X-UIDH: ...    X-Csrf-Token,X-CSRFToken,X-XSRF-TOKEN 防止跨站請求偽造    X-Csrf-Token: i8XNjC4b8KVok4uw5RftR38Wgp2BFwql    X-Request-ID,X-Correlation-ID 標識客戶端和服務端的HTTP請求    X-Request-ID: f058ebd6-02f7-4d3f-942e-904344e8cde5    常用標準響應頭欄位  Access-Control-Allow-Origin 指定哪些站點可以參與跨站資源共享    Access-Control-Allow-Origin: *    Accept-Patch 指定伺服器支援的修補程式文檔格式,適用於http的patch方法    Accept-Patch: text/example;charset=utf-8    Accept-Ranges 伺服器通過byte serving支援的部分內容範圍類型    Accept-Ranges: bytes    Age 對象在代理快取中暫存的秒數    Age: 12    Allow 設置特定資源的有效行為,適用方法不被允許的http 405錯誤    Allow: GET, HEAD    Alt-Svc 伺服器使用"Alt-Svc"(Alternative Servicesde的縮寫)頭標識資源可以通過不同的網路位置或者不同的網路協議獲取    Alt-Svc: h2="http2.example.com:443"; ma=7200    Cache-Control 告訴服務端到客戶端所有的快取機制是否可以快取這個對象,單位是秒    Cache-Control: max-age=3600    Connection 設置當前連接和hop-by-hop協議請求欄位列表的控制選項    Connection: close    Content-Disposition 告訴客戶端彈出一個文件下載框,並且可以指定下載文件名    Content-Disposition: attachment; filename="fname.ext"    Content-Encoding 設置數據使用的編碼類型    Content-Encoding: gzip    Content-Language 為封閉內容設置自然語言或者目標用戶語言    Content-Language: en    Content-Length 響應體的位元組長度    Content-Length: 348    Content-Location 設置返回數據的另一個位置    Content-Location: /index.htm    Content-MD5 設置基於MD5演算法對響應體內容進行Base64二進位編碼    Content-MD5: Q2hlY2sgSW50ZWdyaXR5IQ==    Content-Range 標識響應體內容屬於完整消息體中的那一部分    Content-Range: bytes 21010-47021/47022    Content-Type 設置響應體的MIME類型    Content-Type: text/html; charset=utf-8    Date 設置消息發送的日期和時間    Date: Tue, 15 Nov 1994 08:12:31 GMT    ETag 特定版本資源的標識符,通常是消息摘要    ETag: "737060cd8c284d8af7ad3082f209582d"    Expires 設置響應體的過期時間    Expires: Thu, 01 Dec 1994 16:00:00 GMT    Last-Modified 設置請求對象最後一次的修改日期    Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT    Link 設置與其他資源的類型關係    Link: </feed>; rel="alternate"    Location 在重定向中或者創建新資源時使用    Location: http://www.w3.org/pub/WWW/People.html    P3P 以P3P:CP="your_compact_policy"的格式設置支援P3P(Platform for Privacy Preferences Project)策略,大部分瀏覽器沒有完全支援P3P策略,許多站點設置假的策略內容欺騙支援P3P策略的瀏覽器以獲取第三方cookie的授權    P3P: CP="This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 for more info."    Pragma 設置特殊實現欄位,可能會對請求響應鏈有多種影響    Pragma: no-cache    Proxy-Authenticate 設置訪問代理的請求許可權    Proxy-Authenticate: Basic    Public-Key-Pins 設置站點的授權TLS證書    Public-Key-Pins: max-age=2592000; pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=";    Refresh "重定向或者新資源創建時使用,在頁面的頭部有個擴展可以實現相似的功能,並且大部分瀏覽器都支援  <meta http-equiv="refresh" content="5; url=http://example.com/">    Refresh: 5; url=http://www.w3.org/pub/WWW/People.html    Retry-After 如果實體暫時不可用,可以設置這個值讓客戶端重試,可以使用時間段(單位是秒)或者HTTP時間    Example 1: Retry-After: 120  Example 2: Retry-After: Fri, 07 Nov 2014 23:59:59 GMT    Server 伺服器名稱    Server: Apache/2.4.1 (Unix)    Set-Cookie 設置HTTP Cookie    Set-Cookie: UserID=JohnDoe; Max-Age=3600; Version=1    Status 設置HTTP響應狀態    Status: 200 OK    Strict-Transport-Security 一種HSTS策略通知HTTP客戶端快取HTTPS策略多長時間以及是否應用到子域    Strict-Transport-Security: max-age=16070400; includeSubDomains    Trailer 標識給定的header欄位將展示在後續的chunked編碼的消息中    Trailer: Max-Forwards    Transfer-Encoding 設置傳輸實體的編碼格式,目前支援的格式:chunked, compress, deflate, gzip, identity    Transfer-Encoding: chunked    TSV Tracking Status Value,在響應中設置給DNT(do-not-track),可能的取值     "!" — under construction     "?" — dynamic     "G" — gateway to multiple parties     "N" — not tracking     "T" — tracking     "C" — tracking with consent     "P" — tracking only if consented     "D" — disregarding DNT     "U" — updated    TSV: ?    Upgrade 請求客戶端升級協議    Upgrade: HTTP/2.0, HTTPS/1.3, IRC/6.9, RTA/x11, websocket    Vary 通知下級代理如何匹配未來的請求頭已讓其決定快取的響應是否可用而不是重新從源主機請求新的    Example 1: Vary: *  Example 2: Vary: Accept-Language    Via 通知客戶端代理,通過其要發送什麼響應    Via: 1.0 fred, 1.1 example.com (Apache/1.1)    Warning 實體可能會發生的問題的通用警告    Warning: 199 Miscellaneous warning    WWW-Authenticate 標識訪問請求實體的身份驗證方案    WWW-Authenticate: Basic    X-Frame-Options 點擊劫持保護:     deny frame中不渲染     sameorigin 如果源不匹配不渲染     allow-from 允許指定位置訪問     allowall 不標準,允許任意位置訪問    X-Frame-Options: deny    常用非標準響應頭欄位  X-XSS-Protection 過濾跨站腳本    X-XSS-Protection: 1; mode=block    Content-Security-Policy, X-Content-Security-Policy,X-WebKit-CSP 定義內容安全策略    X-WebKit-CSP: default-src 'self'    X-Content-Type-Options 唯一的取值是"",阻止IE在響應中嗅探定義的內容格式以外的其他MIME格式    X-Content-Type-Options: nosniff    X-Powered-By 指定支援web應用的技術    X-Powered-By: PHP/5.4.0    X-UA-Compatible 推薦首選的渲染引擎來展示內容,通常向後兼容,也用於激活IE中內嵌chrome框架插件  <meta http-equiv="X-UA-Compatible" content="chrome=1" />    X-UA-Compatible: IE=EmulateIE7  X-UA-Compatible: IE=edge  X-UA-Compatible: Chrome=1    X-Content-Duration 提供音影片的持續時間,單位是秒,只有Gecko內核瀏覽器支援    X-Content-Duration: 42.666    Upgrade-Insecure-Requests 標識伺服器是否可以處理HTTPS協議    Upgrade-Insecure-Requests: 1    X-Request-ID,X-Correlation-ID 標識一個客戶端和服務端的請求    X-Request-ID: f058ebd6-02f7-4d3f-942e-904344e8cde5