Java 實現的斷點下載

jopen 9年前發布 | 4K 次閱讀 Java

該斷點下載可應用于瀏覽器或者迅雷等下載工具的下載,實現方式有多種多樣的,本文只研究了單線程的下載,迅雷等下載工具會自動將下載資源分塊并記錄每塊的起始位置,然后根據系統性能,起多線程下載。

1. 基本原理

從Request Header的Range信息里面獲取已經下載的文件大小,然后創建response的outputstream 向客戶端(瀏覽器或者迅雷等下載工具)寫,寫的時候又利用header里面的“Content-Range”, 讓客戶端知道從哪個位置開始寫;

讀取網絡資源方面,利用HttpClient模擬request請求,發起post或者get請求,只是這個請求跟一般請求有點不一樣:需要帶上Range信息,告訴程序該從哪個位置開始讀數據。

2. 需要使用的Java 組件

  • HttpServletRequest / Response
  • HttpClient
  • ServletOutputStream
  • BufferedInputStream

3. 代碼實現

    /**

     * @desc 斷點下載工具方法 
     * @param request 
     * @param response 
     * @param fileLength 
     * @param contentType 
     * @param fileName 
     * @param fileId 
     */  
    public static void resumeDownload(HttpServletRequest request,  
            HttpServletResponse response, Long fileLength, String contentType,  
            String fileName, String fileId) {  
        ServletOutputStream out = null;  
        response.reset();  

        // 記錄斷點續傳的開始點  
        long pos = 0;  
        if (null != request.getHeader("Range")) {  
            response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);  
            try {  
                pos = Long.parseLong(request.getHeader("Range")  
                        .replaceAll("bytes=", "").replaceAll("-.*", ""));  
            } catch (NumberFormatException e) {  
                LOGGER.error(e.getMessage(), e);  
                pos = 0;  
            }  
            String contentRange = new StringBuffer("bytes ").append(pos + "")  
                    .append("-").append((fileLength.intValue() - 1) + "")  
                    .append("/").append(fileLength.intValue() + "").toString();  
            response.setHeader("Content-Range", contentRange);  
        }  

        response.setHeader("Accept-Ranges", "bytes");  
        response.setHeader("Content-Length",  
                String.valueOf(fileLength.intValue() - pos));  
        response.setCharacterEncoding("UTF-8");  
        response.setContentType(contentType);  
        response.setHeader("Content-disposition", "attachment;filename=\""  
                + fileName + "\"");  
        try {  
            out = response.getOutputStream();  
        } catch (IOException e) {  
            LOGGER.error(e.getMessage(), e);  
        }  

        // 斷點下載  
        CloseableHttpClient httpClient = HttpClients.createDefault();  

        HttpPost httpPost = new HttpPost(SysConf.getString("fezo.download.url"));  

        List<NameValuePair> nvps = new ArrayList<NameValuePair>();  
        nvps.add(new BasicNameValuePair(SysConf.getString("fezo.download.param"), fileId));  

        HttpResponse httpResponse = null;  
        BufferedInputStream input = null;  
        try {  
            httpPost.setEntity(new UrlEncodedFormEntity(nvps));  

            httpPost.setHeader("Range", "bytes=" + pos + "-");  
            httpResponse = httpClient.execute(httpPost);  

            input = new BufferedInputStream(httpResponse.getEntity().getContent());  

            byte[] buffer = new byte[CommonConstants.BUFFER_SIZE];  
            int len = -1;  
            while ((len = input.read(buffer)) != -1) {  
                out.write(buffer, 0, len);  
            }  
            out.flush();  
            out.close();  
            input.close();  
        } catch (UnsupportedEncodingException e) {  
            LOGGER.error(e.getMessage(), e);  
        } catch (ClientProtocolException e) {  
            LOGGER.error(e.getMessage(), e);  
        } catch (IOException e) {  
            // 可以忽略這個異常,有可能是用戶暫停下載,或者迅雷等下載工具分塊下載  
        } finally {  
            try {  
                if (httpClient != null) httpClient.close();  
            } catch(IOException e) {  
                LOGGER.error(e.getMessage(), e);  
            }  
        }  
    }  </pre> 


>>>點擊這里下載代碼
4. 重點與難點

    - 獲取response的輸出流程來向客戶端提供下載功能,而不是簡單的把數據寫入到某個具體的文件,核心代碼:out = response.getOutputStream();

    - 頭信息里面"Range" 和 "Conent-Range" 等信息的處理;

    - 迅雷等多線程分塊下載客戶端下載的處理:還是要處理好"Range" 和 "Conent-Range" 等頭部信息,迅雷會自動將文件內容分塊、記錄起始位置。

來自:http://blog.csdn.net/alli0968/article/details/47337349

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!