java如何分块下载
分块下载的实现方法
分块下载通常用于处理大文件或网络资源,通过将文件分成多个部分并行或顺序下载,提高下载效率或实现断点续传功能。以下是几种常见的实现方式:
使用HTTP Range头
HTTP协议支持通过Range头指定下载文件的某一部分。服务器需要支持Range请求。
URL url = new URL("http://example.com/largefile.zip");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("Range", "bytes=0-999"); // 下载前1000字节
InputStream inputStream = connection.getInputStream();
多线程分块下载
创建多个线程,每个线程负责下载文件的不同部分,最后合并文件。
ExecutorService executor = Executors.newFixedThreadPool(4);
List<Future<FilePart>> futures = new ArrayList<>();
for (int i = 0; i < 4; i++) {
int start = i * chunkSize;
int end = (i + 1) * chunkSize - 1;
futures.add(executor.submit(new DownloadTask(url, start, end)));
}
// 合并下载的部分
断点续传实现
记录已下载的字节位置,在中断后从该位置继续下载。
RandomAccessFile file = new RandomAccessFile("output.zip", "rw");
long downloaded = file.length();
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("Range", "bytes=" + downloaded + "-");
file.seek(downloaded);
使用NIO提高性能
Java NIO的FileChannel可以更高效地写入文件块。

FileChannel channel = new RandomAccessFile("output.zip", "rw").getChannel();
FileChannel.MapMode mode = FileChannel.MapMode.READ_WRITE;
MappedByteBuffer buffer = channel.map(mode, position, chunkSize);
注意事项
- 检查服务器是否支持
Range请求(响应头包含Accept-Ranges: bytes) - 正确处理HTTP 206(Partial Content)响应码
- 多线程下载时注意线程安全和文件合并顺序
- 大文件下载考虑内存管理,避免OOM错误
完整示例代码
public class ChunkDownloader {
public static void download(String fileURL, String savePath, int chunks) throws IOException {
long fileSize = getFileSize(fileURL);
long chunkSize = fileSize / chunks;
ExecutorService executor = Executors.newFixedThreadPool(chunks);
List<Future<byte[]>> results = new ArrayList<>();
for (int i = 0; i < chunks; i++) {
long start = i * chunkSize;
long end = (i == chunks - 1) ? fileSize - 1 : start + chunkSize - 1;
results.add(executor.submit(() -> downloadChunk(fileURL, start, end)));
}
try (RandomAccessFile file = new RandomAccessFile(savePath, "rw")) {
for (int i = 0; i < chunks; i++) {
byte[] data = results.get(i).get();
file.seek(i * chunkSize);
file.write(data);
}
}
executor.shutdown();
}
private static long getFileSize(String fileURL) throws IOException {
HttpURLConnection conn = (HttpURLConnection) new URL(fileURL).openConnection();
conn.setRequestMethod("HEAD");
return conn.getContentLengthLong();
}
private static byte[] downloadChunk(String fileURL, long start, long end) throws IOException {
HttpURLConnection conn = (HttpURLConnection) new URL(fileURL).openConnection();
conn.setRequestProperty("Range", "bytes=" + start + "-" + end);
try (InputStream in = conn.getInputStream();
ByteArrayOutputStream out = new ByteArrayOutputStream()) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
return out.toByteArray();
}
}
}
以上方法可以根据实际需求进行调整,如添加进度监控、错误处理等额外功能。






