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

Java 實現斷點續傳下載:HTTP Range、RandomAccessFile 與多線程斷點續傳引擎完整實現

     編輯:Java 相關知識

核心原理:HTTP Range 請求

標準下載請求:

GET /file.zip HTTP/1.1
Host: example.com

斷點續傳請求 (從 2,000,070 字節開始):

GET /file.zip HTTP/1.1
Host: example.com
Range: bytes=2000070-
User-Agent: NetFox

伺服器響應 206 Partial Content:

HTTP/1.1 206 Partial Content
Content-Range: bytes 2000070-106786027/106786028
Content-Length: 104785958
Content-Type: application/octet-stream
Accept-Ranges: bytes

關鍵頭:Range (請求)、Content-Range (響應)、Accept-Ranges: bytes (伺服器支援聲明)。

Java 單線程斷點續傳核心代碼


public class ResumeDownloader {
    public static void download(String urlStr, String destPath, long startPos) throws IOException {
        URL url = new URL(urlStr);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestProperty("User-Agent", "Java-ResumeDownloader/1.0");
        conn.setRequestProperty("Range", "bytes=" + startPos + "-");

        try (InputStream in = conn.getInputStream();
             RandomAccessFile raf = new RandomAccessFile(destPath, "rw")) {

            raf.seek(startPos); // 定位寫入位置
            byte[] buffer = new byte[8192];
            int len;
            while ((len = in.read(buffer)) != -1) {
                raf.write(buffer, 0, len);
            }
        }
    }
}

生產級多線程斷點續傳引擎架構

核心組件

  • SiteFileFetch (主控線程):獲取文件長度、分割任務、啟動/監控工作線程、持久化進度。
  • FileSplitterFetch (工作線程):負責特定區間下載、寫入文件、報告進度。
  • FileAccess (文件訪問封裝):RandomAccessFile 線程安全寫入、位置管理。
  • SiteInfoBean (任務配置):URL、保存路徑、分片數、代理設置等。
  • ProgressPersistence (進度持久化):定期序列化各分片 startPos/endPos 到 .info 文件,支援崩潰恢復。

任務分割策略


// 文件長度 L,分片數 N
long chunkSize = L / N;
for (int i = 0; i < N; i++) {
    long start = i * chunkSize;
    long end = (i == N - 1) ? L : start + chunkSize; // 最後一片包含餘數
    // 創建 FileSplitterFetch(start, end)
}

進度持久化與恢復


// 寫入 .info 文件 (DataOutputStream)
output.writeInt(splitters.length);
for (Splitter s : splitters) {
    output.writeLong(s.getCurrentPos());
    output.writeLong(s.getEndPos());
}

// 讀取恢復
int count = input.readInt();
for (int i = 0; i < count; i++) {
    splitters[i].setCurrentPos(input.readLong());
    splitters[i].setEndPos(input.readLong());
}

線程協作模式:生產者-消費者 (連接池優化)

  • 固定大小工作線程池 (如 5-10)。
  • 主線程將分片任務放入 BlockingQueue。
  • 工作線程從隊列取任務執行,完成後回報。
  • 避免頻繁創建/銷毀線程,控制併發連接數,防止觸發伺服器限流。

完整項目結構 (簡化)

netfox/
├── SiteFileFetch.java        // 主控線程
├── FileSplitterFetch.java    // 工作線程
├── FileAccess.java           // RandomAccessFile 封裝
├── SiteInfoBean.java         // 配置 Bean
├── ProgressPersistence.java  // 進度持久化
├── Util.java                 // 日誌、睡眠工具
└── TestMain.java             // 測試入口

關鍵工程化細節

問題解決方案
伺服器不支援 Range檢測響應碼 200 且無 Accept-Ranges → 降級單線程下載
網絡波動導致讀取 -1捕獲 IOException,指數退避重試 (最多 3 次),記錄斷點
大文件 (GB 級) 內存壓力流式讀寫、緩衝區 8KB-64KB、避免載入整個文件
多線程寫入同一文件衝突RandomAccessFile seek 定位 + synchronized 寫入鎖 / 分片互不重疊天然無衝突
進度文件損壞/丟失校驗和 (CRC32) 驗證、備份舊版本、啟動時完整性檢查
用戶暫停/取消volatile boolean stopFlag,工作線程定期檢查並安全退出

現代替代:OkHttp / Apache HttpClient 5


// OkHttp 斷點續傳 (自動處理 Range、重試、連接池)
Request request = new Request.Builder()
    .url(url)
    .header("Range", "bytes=" + downloaded + "-")
    .build();

try (Response response = client.newCall(request).execute();
     InputStream in = response.body().byteStream();
     RandomAccessFile raf = new RandomAccessFile(file, "rw")) {
    raf.seek(downloaded);
    byte[] buffer = new byte[8192];
    int len;
    while ((len = in.read(buffer)) != -1) raf.write(buffer, 0, len);
}

總結

斷點續傳核心在於 HTTP Range 標準 + RandomAccessFile 隨機寫入 + 進度持久化。單線程易實現,生產級引擎需解決 分片策略、線程池協作、斷點恢復、異常重試、伺服器兼容性、用戶控制 等工程化問題。理解底層協議與 I/O 模型,方能構建健壯的下載引擎;現代項目建議直接使用成熟 HTTP 客戶端庫 (OkHttp、HttpClient 5) 組裝業務邏輯,避免重複造輪子。

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