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

Java URL 下載遠端檔案完整實作:HTTP/HTTPS/FTP 通用方案

     編輯:Java 相關知識

Java 提供 java.net.URL 與 URLConnection 實現統一的資源存取介面,支援 HTTP、HTTPS、FTP 等協議。本文提供生產級下載工具類,涵蓋斷點續傳、進度回呼、連線池、SSL 忽略憑證等進階功能。

基礎下載實作 (阻塞式)

public boolean download(String urlString, String destPath) {
    try (InputStream in = new URL(urlString).openStream();
         FileOutputStream out = new FileOutputStream(destPath)) {
        
        byte[] buffer = new byte[8192];
        int bytesRead;
        while ((bytesRead = in.read(buffer)) != -1) {
            out.write(buffer, 0, bytesRead);
        }
        return true;
    } catch (IOException e) {
        log.error("Download failed: {}", urlString, e);
        return false;
    }
}

進階 HTTP/HTTPS 下載器 (支援斷點續傳)

public class HttpDownloader {
    private static final int BUFFER_SIZE = 8192;
    private static final int CONNECT_TIMEOUT = 10_000;
    private static final int READ_TIMEOUT = 30_000;

    public void download(String urlString, File destFile, ProgressListener listener) 
            throws IOException {
        
        long existingLength = destFile.exists() ? destFile.length() : 0;
        URL url = new URL(urlString);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        
        // 設定連線參數
        conn.setConnectTimeout(CONNECT_TIMEOUT);
        conn.setReadTimeout(READ_TIMEOUT);
        conn.setRequestProperty("User-Agent", "Java Downloader 1.0");
        
        // 斷點續傳:Range 標頭
        if (existingLength > 0) {
            conn.setRequestProperty("Range", "bytes=" + existingLength + "-");
        }
        
        int responseCode = conn.getResponseCode();
        if (responseCode == HttpURLConnection.HTTP_PARTIAL || responseCode == HttpURLConnection.HTTP_OK) {
            long contentLength = conn.getContentLengthLong();
            long totalLength = existingLength + contentLength;
            
            try (InputStream in = conn.getInputStream();
                 RandomAccessFile raf = new RandomAccessFile(destFile, "rw")) {
                
                raf.seek(existingLength);
                byte[] buffer = new byte[BUFFER_SIZE];
                int bytesRead;
                long downloaded = existingLength;
                
                while ((bytesRead = in.read(buffer)) != -1) {
                    raf.write(buffer, 0, bytesRead);
                    downloaded += bytesRead;
                    if (listener != null) {
                        listener.onProgress(downloaded, totalLength);
                    }
                }
            }
        } else if (responseCode == HttpURLConnection.HTTP_RANGE_NOT_SATISFIABLE) {
            // 檔案已完整
            if (listener != null) listener.onProgress(existingLength, existingLength);
        } else {
            throw new IOException("Server returned: " + responseCode);
        }
    }

    @FunctionalInterface
    public interface ProgressListener {
        void onProgress(long downloaded, long total);
    }
}

HTTPS 忽略自簽憑證 (僅測試環境)

// 必須在建立連線前設置
TrustManager[] trustAll = new TrustManager[] {
    new X509TrustManager() {
        public void checkClientTrusted(X509Certificate[] chain, String authType) {}
        public void checkServerTrusted(X509Certificate[] chain, String authType) {}
        public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
    }
};
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAll, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true);

FTP 協議支援

// URL 格式:ftp://user:pass@host:port/path/to/file
URL url = new URL("ftp://user:password@ftp.example.com/pub/file.zip");
URLConnection conn = url.openConnection();
// FTP 不支援 Range 斷點續傳,需使用 Apache Commons Net FTPClient

生產環境建議:改用成熟函式庫

效能優化清單

  • 啟用 GZIP 壓縮:conn.setRequestProperty("Accept-Encoding", "gzip")
  • 使用 BufferedInputStream/BufferedOutputStream 減少系統呼叫
  • 大檔案採用 FileChannel.transferFrom() 零拷貝 (NIO)
  • 並行下載:分割檔案多執行緒下載合併 (需支援 Range)
  • 連線池複用:HttpClient PoolingHttpClientConnectionManager

結語

Java 原生 URL/URLConnection 足夠應付簡單下載需求,但生產環境強烈建議使用 Apache HttpClient 或 OkHttp 獲得連線池、重試、非同步、HTTP/2 等企業級特性。斷點續傳需伺服端支援 Accept-Ranges: bytes,FTP 協議請改用 Commons Net。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
函式庫Maven 坐標特色
Apache HttpClientorg.apache.httpcomponents:httpclient:4.5.x連線池、重試、攔截器、非同步、完整 HTTP/1.1
OkHttpcom.squareup.okhttp3:okhttp:4.xHTTP/2、連線池、透明 GZIP、現代 API
Spring RestTemplate/WebClientorg.springframework:spring-webSpring 生態整合、宣告式重試、反應式
Apache Commons Netcommons-net:commons-net:3.xFTP/FTPS/SFTP 完整支援