在 Java 開發中,透過 HTTP 協議下載文件是常見需求。本文提供一個完整、可直接運行的範例,展示如何使用 HttpURLConnection 實現文件下載,包含文件名解析、進度顯示、異常處理等關鍵技術點。
下載流程主要包含四個步驟:建立連接、解析文件名、讀取數據流、寫入本地文件。關鍵在於正確處理 Content-Disposition 響應頭以獲取原始文件名,並對 URL 編碼的文件名進行解碼。
package com.hongyuan.test;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
public class FileDownload {
public static final String LOCAL_PATH = "d:/";
public static void main(String[] args) {
// 待下載文件地址
String fileUrl = "https://211.162.55.16/cdn.百度pcs.com/file/6a73dab7c03023a9835cc737f447674d?xcode=af6ffdc43a44169bac968d32c4bd420084a9a97c308112c9&fid=3255571826-250528-130564002&time=1397293108&sign=FDTAXER-DCb740ccc5511e5e8fedcff06b081203-mQkOeRDtXpyQWwYJkI%2BxKJpxn5k%3D&to=cb&fm=N,B,U,nc&newver=1&expires=1397297563&rt=sh&r=854979042&logid=1751715936&sh=1&vuk=3255571826&fn=Web%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%20%E7%AC%AC5%E7%89%88.pdf&wshc_tag=0&wsiphost=ipdbm";
InputStream in = null;
OutputStream out = null;
HttpURLConnection conn = null;
String fileName = null;
try {
// 初始化連接
URL url = new URL(fileUrl);
conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(true);
// 獲取文件名
String disposition = conn.getHeaderField("Content-Disposition");
if (disposition != null && !"".equals(disposition)) {
// 從響應頭中獲取文件名
fileName = disposition.split(";")[1].split("=")[1].replaceAll("\"", "");
} else {
// 從 URL 中獲取文件名
fileName = fileUrl.substring(fileUrl.lastIndexOf("/") + 1);
}
if (fileName != null && !"".equals(fileName)) {
// 文件名解碼
fileName = URLDecoder.decode(fileName, "utf-8");
} else {
// 若無法獲取文件名,則隨機生成一個
fileName = "file_" + (int)(Math.random() * 10);
}
// 讀取數據
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
byte[] buffer = new byte[2048];
in = conn.getInputStream();
out = new FileOutputStream(new File(LOCAL_PATH, fileName));
int count = 0;
int finished = 0;
int size = conn.getContentLength();
while ((count = in.read(buffer)) != -1) {
if (count != 0) {
out.write(buffer, 0, count);
finished += count;
System.out.printf("########################################---->%1$.2f%%\n", (double)finished / size * 100);
} else {
break;
}
}
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (out != null) out.close();
if (in != null) in.close();
if (conn != null) conn.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
setDoInput(true) 和 setDoOutput(true) 啟用輸入輸出流Content-Disposition 響應頭解析,失敗則從 URL 提取URLDecoder.decode() 處理 URL 編碼的中文文件名Content-Length 計算下載百分比,實時輸出進度條finally 塊確保流和連接正確關閉,防止資源洩漏生產環境中建議增加:斷點續傳支持(Range 請求頭)、多線程分塊下載、下載速度限制、更完善的異常重試機制。對於大文件,建議使用 BufferedInputStream 和 BufferedOutputStream 提升 I/O 效率。