首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 實現檔案斷點續傳下載:HTTP Range 請求完整範例

     編輯:Java 相關知識

斷點續傳下載的核心在於支援 HTTP Range 標頭,讓客戶端可指定下載位元組區間。下面提供一個基於 Servlet 的完整實現,支援瀏覽器與迅雷等多線程下載工具。

核心邏輯:downloadFileRanges

private void downloadFileRanges(File file) throws IOException {
    long fileLength = file.length();
    long pastLength = 0;
    boolean isFlashGet = true;  // true: 瀏覽器/閃獲;false: 迅雷等多線程
    long lenEnd = 0;

    String rangeHeader = request.getHeader("Range");
    RandomAccessFile raf = null;
    OutputStream out = null;
    byte[] buffer = new byte[1024];

    try {
        // 1. 解析 Range 標頭
        if (rangeHeader != null) {
            response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); // 206
            rangeHeader = rangeHeader.replaceAll("bytes=", "");
            
            if (rangeHeader.endsWith("-")) {  // bytes=100-  瀏覽器單線程
                pastLength = Long.parseLong(rangeHeader.substring(0, rangeHeader.indexOf('-')));
            } else {  // bytes=100-200  迅雷多線程
                isFlashGet = false;
                String[] parts = rangeHeader.split("-");
                pastLength = Long.parseLong(parts[0]);
                lenEnd = Long.parseLong(parts[1]);
            }
        }

        // 2. 回應標頭:宣告支援斷點續傳
        response.setHeader("Accept-Ranges", "bytes");
        if (pastLength > 0) {
            String contentRange = isFlashGet 
                ? "bytes " + pastLength + "-" + (fileLength - 1) + "/" + fileLength
                : "bytes " + rangeHeader + "/" + fileLength;
            response.setHeader("Content-Range", contentRange);
        }

        // 3. 設定下載檔名與內容類型
        String fileName = new String(filename.getBytes("GBK"), "ISO8859-1");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
        response.setContentType("application/octet-stream");
        response.addHeader("Content-Length", String.valueOf(fileLength));

        // 4. 核心傳輸邏輯
        raf = new RandomAccessFile(file, "r");
        out = new BufferedOutputStream(response.getOutputStream());
        raf.seek(pastLength);

        if (isFlashGet) {
            int n;
            while ((n = raf.read(buffer)) != -1) {
                out.write(buffer, 0, n);
            }
        } else {
            while (raf.getFilePointer() < lenEnd) {
                out.write(raf.read());
            }
        }
        out.flush();
    } catch (ClientAbortException e) {
        log.debug("客戶端取消下載"); // 正常現象,忽略
    } finally {
        if (out != null) out.close();
        if (raf != null) raf.close();
    }
}

關鍵點解析

  1. Range 解析: 區分「無結尾位元組」(瀏覽器續傳)與「有起訖位元組」(迅雷分片下載)。
  2. 206 Partial Content: 只有收到 Range 請求時才回傳 206,否則預設 200 全檔下載。
  3. Content-Range: 告知客戶端本次傳輸的位元組區間與總大小。
  4. RandomAccessFile: 透過 seek() 直接定位到斷點位置,避免讀取已下載資料。
  5. 異常處理: 捕獲 ClientAbortException(客戶端中斷),防止伺服器日誌汙染;迅雷會開啟多線程搶佔同一區塊,導致多個此異常,屬正常行為。
  6. 中文檔名編碼: 以 GBK → ISO8859-1 轉碼相容大多數瀏覽器。

Struts 2 與 JSP 整合

<!-- struts.xml -->
<action name="downloadFile" class="downloadFileAction" method="downloadFile">
    <result name="failed" type="redirectAction">showDownloadFileNameList</result>
</action>

<!-- JSP 下載連結 -->
<a href="downloadFile?filename=${fileMap.key}&filepath=${fileMap.value}">檔案下載</a>

此實現已在生產環境驗證,可支援大檔案、多線程下載工具與瀏覽器原生續傳功能。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved