本文目录导读:

我来详细讲解Java实现文件下载的几种常见方式。
基础HTTP文件下载(URL Connection)
简单文件下载
import java.io.*;
import java.net.*;
public class FileDownloader {
public static void downloadFile(String fileURL, String savePath) throws IOException {
URL url = new URL(fileURL);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 设置请求属性
connection.setRequestMethod("GET");
connection.setConnectTimeout(5000);
connection.setReadTimeout(5000);
// 获取输入流
try (InputStream inputStream = connection.getInputStream();
FileOutputStream outputStream = new FileOutputStream(savePath)) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
}
System.out.println("文件下载完成: " + savePath);
}
public static void main(String[] args) {
try {
downloadFile("https://example.com/file.pdf", "downloaded_file.pdf");
} catch (IOException e) {
e.printStackTrace();
}
}
}
带进度条的下载
public class FileDownloadWithProgress {
public static void downloadWithProgress(String fileURL, String savePath) throws IOException {
URL url = new URL(fileURL);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 获取文件大小
int fileSize = connection.getContentLength();
System.out.println("文件大小: " + fileSize + " bytes");
try (InputStream inputStream = connection.getInputStream();
FileOutputStream outputStream = new FileOutputStream(savePath)) {
byte[] buffer = new byte[4096];
int bytesRead;
int totalBytesRead = 0;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
totalBytesRead += bytesRead;
// 计算并显示进度
if (fileSize > 0) {
int progress = (int) ((totalBytesRead * 100) / fileSize);
System.out.print("\r下载进度: " + progress + "%");
}
}
System.out.println("\n下载完成!");
}
}
}
断点续传下载
public class ResumeDownload {
public static void resumeDownload(String fileURL, String savePath) throws IOException {
File file = new File(savePath);
long existingFileSize = 0;
// 检查是否已有部分下载的文件
if (file.exists()) {
existingFileSize = file.length();
System.out.println("已有部分下载文件,大小: " + existingFileSize + " bytes");
}
URL url = new URL(fileURL);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 设置断点续传请求头
if (existingFileSize > 0) {
connection.setRequestProperty("Range", "bytes=" + existingFileSize + "-");
}
int responseCode = connection.getResponseCode();
// 206表示部分内容,支持断点续传
if (responseCode == HttpURLConnection.HTTP_PARTIAL || responseCode == HttpURLConnection.HTTP_OK) {
try (InputStream inputStream = connection.getInputStream();
FileOutputStream outputStream = new FileOutputStream(savePath, true)) {
byte[] buffer = new byte[4096];
int bytesRead;
long totalBytesRead = existingFileSize;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
totalBytesRead += bytesRead;
System.out.print("\r已下载: " + totalBytesRead + " bytes");
}
System.out.println("\n下载完成!");
}
}
}
}
使用Apache HttpClient
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.HttpEntity;
public class HttpClientDownload {
public static void downloadWithHttpClient(String fileURL, String savePath) throws Exception {
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
HttpGet httpGet = new HttpGet(fileURL);
try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
HttpEntity entity = response.getEntity();
if (entity != null) {
try (InputStream inputStream = entity.getContent();
FileOutputStream outputStream = new FileOutputStream(savePath)) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
}
}
}
}
System.out.println("下载完成");
}
}
Web应用中的文件下载(Servlet)
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
@WebServlet("/download")
public class FileDownloadServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String fileName = request.getParameter("file");
String filePath = "/path/to/your/files/" + fileName;
File file = new File(filePath);
if (!file.exists()) {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
// 设置响应头
response.setContentType("application/octet-stream");
response.setContentLength((int) file.length());
response.setHeader("Content-Disposition",
"attachment; filename=\"" + fileName + "\"");
// 写入文件内容
try (FileInputStream inputStream = new FileInputStream(file);
OutputStream outputStream = response.getOutputStream()) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
}
}
}
多线程下载
public class MultiThreadDownload {
private static final int THREAD_COUNT = 4;
public static void downloadWithMultiThread(String fileURL, String savePath) throws Exception {
URL url = new URL(fileURL);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
int fileSize = connection.getContentLength();
connection.disconnect();
int partSize = fileSize / THREAD_COUNT;
List<DownloadThread> threads = new ArrayList<>();
// 创建并启动多个下载线程
for (int i = 0; i < THREAD_COUNT; i++) {
int start = i * partSize;
int end = (i == THREAD_COUNT - 1) ? fileSize - 1 : (start + partSize - 1);
DownloadThread thread = new DownloadThread(fileURL, savePath, start, end, i);
threads.add(thread);
thread.start();
}
// 等待所有线程完成
for (DownloadThread thread : threads) {
thread.join();
}
// 合并文件
mergeFiles(savePath, THREAD_COUNT);
}
static class DownloadThread extends Thread {
private String fileURL;
private String savePath;
private int start;
private int end;
private int threadId;
public DownloadThread(String fileURL, String savePath, int start, int end, int threadId) {
this.fileURL = fileURL;
this.savePath = savePath;
this.start = start;
this.end = end;
this.threadId = threadId;
}
@Override
public void run() {
try {
URL url = new URL(fileURL);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("Range", "bytes=" + start + "-" + end);
try (InputStream inputStream = connection.getInputStream();
RandomAccessFile outputFile = new RandomAccessFile(savePath + ".part" + threadId, "rw")) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputFile.write(buffer, 0, bytesRead);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static void mergeFiles(String savePath, int threadCount) throws IOException {
try (FileOutputStream outputStream = new FileOutputStream(savePath)) {
for (int i = 0; i < threadCount; i++) {
File partFile = new File(savePath + ".part" + i);
try (FileInputStream inputStream = new FileInputStream(partFile)) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
}
partFile.delete();
}
}
}
}
异常处理与重试机制
public class DownloadWithRetry {
private static final int MAX_RETRIES = 3;
private static final int RETRY_DELAY_MS = 2000;
public static void downloadWithRetry(String fileURL, String savePath) {
int retries = 0;
boolean success = false;
while (retries < MAX_RETRIES && !success) {
try {
downloadFile(fileURL, savePath);
success = true;
System.out.println("下载成功");
} catch (IOException e) {
retries++;
System.err.println("下载失败 (尝试 " + retries + "/" + MAX_RETRIES + "): " + e.getMessage());
if (retries < MAX_RETRIES) {
try {
Thread.sleep(RETRY_DELAY_MS);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
break;
}
}
}
}
if (!success) {
System.err.println("下载失败,已重试 " + MAX_RETRIES + " 次");
}
}
}
完整的使用示例
public class CompleteDownloadExample {
public static void main(String[] args) {
String fileURL = "https://example.com/large-file.zip";
String savePath = "downloads/large-file.zip";
// 创建下载目录
new File("downloads").mkdirs();
try {
// 基础下载
// FileDownloader.downloadFile(fileURL, savePath);
// 带进度条下载
// FileDownloadWithProgress.downloadWithProgress(fileURL, savePath);
// 断点续传
// ResumeDownload.resumeDownload(fileURL, savePath);
// 多线程下载
// MultiThreadDownload.downloadWithMultiThread(fileURL, savePath);
} catch (Exception e) {
e.printStackTrace();
}
}
}
- 资源管理:使用 try-with-resources 自动关闭流
- 缓冲处理:使用缓冲区提高性能(4096 bytes 是常用值)
- 异常处理:处理网络超时、文件不存在等情况
- 编码问题:正确处理文件名编码
- 大文件处理:考虑使用断点续传或多线程下载
- 安全性:验证URL合法性,防止路径遍历攻击
选择哪种方式取决于你的具体需求,如文件大小、网络稳定性、是否需要断点续传等。