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

Java 從網絡下載圖片到本地的簡潔實現

     編輯:Java 相關知識

本文提供一個簡潔的 Java 方法,使用標準 java.net.URL 與輸入輸出流實現從網絡下載圖片並保存到本地。代碼包含目錄自動創建、緩衝讀寫、異常處理等實用細節。

核心代碼


import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;

public class ImageDownloader {

    /**
     * 從網絡下載圖片並保存到本地
     * @param imageUrl  圖片完整 URL
     * @param fileName  保存的文件名(含副檔名)
     * @param saveDir   保存目錄(會自動創建)
     */
    public static void downloadImage(String imageUrl, String fileName, String saveDir) {
        URL url = null;
        try {
            url = new URL(imageUrl);
        } catch (MalformedURLException e) {
            System.err.println("無效的 URL 格式: " + imageUrl);
            e.printStackTrace();
            return;
        }

        // 創建保存目錄
        File dir = new File(saveDir);
        if (!dir.exists()) {
            boolean created = dir.mkdirs();
            if (!created) {
                System.err.println("無法創建目錄: " + saveDir);
                return;
            }
        }

        File outputFile = new File(dir, fileName);
        
        try (InputStream is = url.openStream();
             FileOutputStream os = new FileOutputStream(outputFile)) {
            
            byte[] buffer = new byte[8192]; // 8KB 緩衝區
            int bytesRead;
            while ((bytesRead = is.read(buffer)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            System.out.println("下載成功: " + outputFile.getAbsolutePath());
            
        } catch (IOException e) {
            System.err.println("下載失敗: " + e.getMessage());
            e.printStackTrace();
        }
    }

    // 測試主方法
    public static void main(String[] args) {
        String url = "https://example.com/image.jpg";
        downloadImage(url, "downloaded.jpg", "d:/webimg/");
    }
}

關鍵實現細節

進階增強版(支援連接超時、重試、進度回調)


import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.function.Consumer;

public class AdvancedImageDownloader {

    public static void downloadWithProgress(String imageUrl, String fileName, String saveDir,
            int connectTimeout, int readTimeout, int maxRetries,
            Consumer<Double> progressCallback) throws IOException {
        
        File dir = new File(saveDir);
        dir.mkdirs();
        File outputFile = new File(dir, fileName);
        
        int attempt = 0;
        IOException lastException = null;
        
        while (attempt <= maxRetries) {
            try {
                URL url = new URL(imageUrl);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setConnectTimeout(connectTimeout);
                conn.setReadTimeout(readTimeout);
                conn.setRequestProperty("User-Agent", "Mozilla/5.0 Java Downloader");
                
                int responseCode = conn.getResponseCode();
                if (responseCode != HttpURLConnection.HTTP_OK) {
                    throw new IOException("HTTP 錯誤碼: " + responseCode);
                }
                
                long contentLength = conn.getContentLengthLong();
                try (InputStream is = conn.getInputStream();
                     FileOutputStream os = new FileOutputStream(outputFile)) {
                    
                    byte[] buffer = new byte[8192];
                    int bytesRead;
                    long totalRead = 0;
                    
                    while ((bytesRead = is.read(buffer)) != -1) {
                        os.write(buffer, 0, bytesRead);
                        totalRead += bytesRead;
                        
                        if (progressCallback != null && contentLength > 0) {
                            double progress = (double) totalRead / contentLength;
                            progressCallback.accept(progress);
                        }
                    }
                }
                return; // 成功返回
                
            } catch (IOException e) {
                lastException = e;
                attempt++;
                if (attempt <= maxRetries) {
                    try { Thread.sleep(1000L * attempt); } catch (InterruptedException ignored) {}
                }
            }
        }
        throw new IOException("重試 " + maxRetries + " 次後仍失敗", lastException);
    }

    // 使用範例
    public static void main(String[] args) {
        try {
            downloadWithProgress(
                "https://example.com/large.jpg",
                "large.jpg",
                "d:/downloads/",
                5000, 30000, 3,
                progress -> System.out.printf("進度: %.1f%%%n", progress * 100)
            );
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

常見問題排查

環節實現方式說明
URL 解析new URL(string)拋出 MalformedURLException 需捕獲
輸入流獲取url.openStream()返回 InputStream,底層建立 HTTP 連接
目錄創建file.mkdirs()遞歸創建多級目錄
緩衝讀寫8KB byte[] + read()/write()避免單字節讀寫效能極差
資源管理try-with-resources (JDK 7+)自動關閉流,防止洩漏
問題原因解決
FileNotFoundExceptionURL 返回 404 或重定向到錯誤頁檢查 URL、模擬瀏覽器 User-Agent
ConnectException: Connection timed out網路不通、防火牆、目標服務器慢增加連接超時、檢查代理、換源
SSLHandshakeExceptionHTTPS 證書驗證失敗信任憑證、或跳過驗證(僅測試用)
下載檔案損壞/為 0 字節流未正確關閉、重定向到 HTML 頁面檢查 Content-Type、確保 try-with-resources

生產環境建議

  • 使用成熟 HTTP 客戶端:Apache HttpClient、OkHttp、Spring RestTemplate/WebClient
  • 支援斷點續傳(Range 請求)、連接池、熔斷、監控指標
  • 大文件考慮磁盤空間、流式處理避免 OOM
  • 合規性:遵守 robots.txt、速率限制、版權授權

總結

標準庫 java.net.URL 簡單直觀,適合輕量級下載需求。生產環境建議升級為專業 HTTP 客戶端,獲得更好的錯誤處理、效能、可觀測性與合規支援。

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