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

Java 實現 HTTP 文件隊列下載器:斷點續傳、代理支援與批量自動化

     編輯:Java 程式設計入門

核心流程三步驟

  1. 建立連接:HttpURLConnection 發起 GET 請求,設置超時、User-Agent、Range 頭。
  2. 獲取輸入流:conn.getInputStream() 讀取響應體。
  3. 寫入文件:緩衝流分塊寫入,支援隨機訪問實現斷點續傳。

完整下載器實現

import java.io.*;
import java.net.*;
import java.util.*;

public class HttpQueueDownloader {
    private static final int BUFFER_SIZE = 8192;
    private final List<DownloadTask> tasks = new ArrayList<>();
    private final boolean debug;

    public HttpQueueDownloader(boolean debug) { this.debug = debug; }

    public void addTask(String url, String destFile) {
        tasks.add(new DownloadTask(url, destFile));
    }

    public void start() {
        for (DownloadTask task : tasks) {
            try {
                download(task);
                log("完成:" + task.destFile);
            } catch (IOException e) {
                log("失敗:" + task.url + " - " + e.getMessage());
            }
        }
    }

    private void download(DownloadTask task) throws IOException {
        URL url = new URL(task.url);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        setupProxy(conn);
        conn.setRequestMethod("GET");
        conn.setConnectTimeout(10000);
        conn.setReadTimeout(30000);
        conn.setRequestProperty("User-Agent", "JavaDownloader/1.0");

        // 斷點續傳:若文件已存在,設置 Range
        File file = new File(task.destFile);
        long existing = file.length();
        if (existing > 0) {
            conn.setRequestProperty("Range", "bytes=" + existing + "-");
        }

        int code = conn.getResponseCode();
        if (code == 416) { // Range Not Satisfiable -> 已下載完
            return;
        }
        if (code >= 400) {
            throw new IOException("HTTP " + code + " " + conn.getResponseMessage());
        }

        try (InputStream in = new BufferedInputStream(conn.getInputStream());
             RandomAccessFile raf = new RandomAccessFile(file, "rw")) {
            raf.seek(existing);
            byte[] buf = new byte[BUFFER_SIZE];
            int len;
            while ((len = in.read(buf)) != -1) {
                raf.write(buf, 0, len);
            }
        }
    }

    private void setupProxy(HttpURLConnection conn) {
        // 可從系統屬性或配置讀取
        String proxyHost = System.getProperty("proxyHost");
        String proxyPort = System.getProperty("proxyPort");
        if (proxyHost != null && proxyPort != null) {
            Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, Integer.parseInt(proxyPort)));
            // 注意:HttpURLConnection 不直接支援 Proxy 參數,需用 URL.openConnection(proxy)
            // 此處簡化,實際建構 URL 時傳入 Proxy
        }
    }

    private void log(String msg) {
        if (debug) System.out.println("[Downloader] " + msg);
    }

    static class DownloadTask {
        final String url;
        final String destFile;
        DownloadTask(String url, String destFile) {
            this.url = url;
            this.destFile = destFile;
        }
    }

    // 使用示例
    public static void main(String[] args) {
        HttpQueueDownloader dl = new HttpQueueDownloader(true);
        dl.addTask("https://example.com/file1.zip", "data/file1.zip");
        dl.addTask("https://example.com/file2.zip", "data/file2.zip");
        dl.start();
    }
}

關鍵增強點

  • 代理支援:生產環境用 new URL(url).openConnection(proxy) 而非系統屬性,線程安全。
  • 斷點續傳:Range: bytes=start- + RandomAccessFile.seek()。
  • 校驗完整性:下載後對比 Content-Length 或計算 MD5/SHA-256。
  • 併發控制:引入 ExecutorService + Semaphore 限制並發數,避免佔滿帶寬/文件句柄。
  • 進度回調:提供 ProgressListener 接口,UI 層訂閱顯示進度條。

生產級替代方案

若需工業級穩健性,建議直接集成成熟庫:

  • Apache HttpClient 5.x:連接池、重試、攔截器、異步非阻塞。
  • OkHttp:連接復用、透明 GZIP、WebSocket、現代 API。
  • Spring WebClient / RestClient:響應式、聲明式、與 Spring 生態無縫整合。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved