Java多线程下载实例详解
本文将介绍Java多线程下载的实现方法和步骤,并提供两个示例说明。
实现步骤
Java多线程下载的实现步骤如下:
- 获取需要下载的文件的URL地址。
- 创建多个线程,每个线程负责下载文件的不同部分。
- 启动多个线程,通过HTTP请求下载各自负责的文件部分。
- 合并下载完成的文件部分。
- 完成文件下载。
示例一:Java多线程文件下载
以下示例是一个基于Java多线程的文件下载器,该程序支持并发下载多个文件,每个文件都会分成多个线程进行下载。
import java.io.File;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MultiThreadFileDownloader {
private String url; // 下载链接
private String fileName; // 本地保存文件名
private String fileSavePath; // 文件保存目录
private int threadNum; // 线程数量
public MultiThreadFileDownloader(String url, String fileSavePath, String fileName, int threadNum) {
this.url = url;
this.fileSavePath = fileSavePath;
this.fileName = fileName;
this.threadNum = threadNum;
}
public void download() throws Exception {
URL fileUrl = new URL(url);
HttpURLConnection connection = (HttpURLConnection) fileUrl.openConnection();
// 获取下载文件长度
int fileSize = connection.getContentLength();
connection.disconnect();
// 保存文件夹不存在则创建
File saveDir = new File(fileSavePath);
if (!saveDir.exists()) {
saveDir.mkdirs();
}
// 计算每个线程要下载的字节数
int blockSize = fileSize / threadNum + 1;
// 创建线程池
ExecutorService executorService = Executors.newCachedThreadPool();
// 创建下载任务
DownloadTask[] downloadTasks = new DownloadTask[threadNum];
for (int i = 0; i < threadNum; i++) {
int startIndex = i * blockSize; // 计算下载起始位置
int endIndex = (i + 1) * blockSize - 1; // 计算下载结束位置
// 最后一个线程下载到文件末尾
if (i == threadNum - 1) {
endIndex = fileSize;
}
// 创建下载任务
DownloadTask downloadTask = new DownloadTask(url, fileSavePath, fileName, startIndex, endIndex);
downloadTasks[i] = downloadTask;
// 将下载任务交给线程池执行
executorService.execute(downloadTask);
}
// 等待所有线程下载完成
for (DownloadTask downloadTask : downloadTasks) {
downloadTask.waitFinish();
}
// 合并下载文件
mergeDownloadFile();
// 关闭线程池
executorService.shutdown();
}
// 合并下载文件
private void mergeDownloadFile() throws Exception {
// 创建下载文件
File downloadFile = new File(fileSavePath + fileName);
RandomAccessFile randomAccessFile = new RandomAccessFile(downloadFile, "rw");
// 遍历所有下载文件块,并将文件块内容依次写入下载文件
for (int i = 0; i < threadNum; i++) {
File downloadTempFile = new File(fileSavePath + fileName + ".temp" + i);
RandomAccessFile tempFile = new RandomAccessFile(downloadTempFile, "r");
byte[] buffer = new byte[1024];
int length;
while ((length = tempFile.read(buffer)) != -1) {
randomAccessFile.write(buffer, 0, length);
}
tempFile.close();
// 删除临时文件
downloadTempFile.delete();
}
randomAccessFile.close();
}
// 下载任务
private class DownloadTask implements Runnable {
private String url; // 下载链接
private String fileSavePath; // 本地保存路径
private String fileName; // 保存文件名
private int startIndex; // 起始下载位置
private int endIndex; // 结束下载位置
private boolean isFinish = false; // 是否下载完成
public DownloadTask(String url, String fileSavePath, String fileName, int startIndex, int endIndex) {
this.url = url;
this.fileSavePath = fileSavePath;
this.fileName = fileName;
this.startIndex = startIndex;
this.endIndex = endIndex;
}
@Override
public void run() {
try {
URL fileUrl = new URL(this.url);
HttpURLConnection connection = (HttpURLConnection) fileUrl.openConnection();
// 设置下载文件的范围
connection.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);
byte[] buffer = new byte[1024];
int length;
int totalLength = 0;
// 创建临时文件
File file = new File(fileSavePath + fileName + ".temp" + Thread.currentThread().getId());
RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
// 获取输入流并将数据写入临时文件
while ((length = connection.getInputStream().read(buffer)) != -1) {
randomAccessFile.write(buffer, 0, length);
totalLength += length;
}
randomAccessFile.close();
connection.disconnect();
// 标记下载任务已经完成
isFinish = true;
} catch (Exception e) {
e.printStackTrace();
}
}
// 等待下载任务完成
public void waitFinish() throws InterruptedException {
while (!isFinish) {
Thread.sleep(100);
}
}
}
}
示例二:Java多线程图片下载
以下示例展示了如何使用Java多线程下载图片,并将其保存到本地磁盘中。
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class MultiThreadImageDownloader {
public static void downloadImage(String imageUrl, String savePath) {
try {
// 获取连接
URL url = new URL(imageUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 获取文件长度
int fileSize = connection.getContentLength();
System.out.println("文件大小为:" + fileSize);
// 分配线程下载
int threadNum = 4;
int blockSize = fileSize / threadNum + 1;
FileDownloadThread[] threads = new FileDownloadThread[threadNum];
// 创建文件夹
File dir = new File(savePath);
if (!dir.exists()) {
dir.mkdirs();
}
// 分别开启多个线程下载不同的文件块
for (int i = 0; i < threadNum; i++) {
int start = i * blockSize;
int end = (i + 1) * blockSize - 1;
if (i == threadNum - 1) {
end = fileSize - 1;
}
System.out.println("线程 " + i + " 下载:" + start + " ~ " + end + " 字节");
FileDownloadThread thread = new FileDownloadThread(url, start, end, new File(savePath + "/" + getFileName(imageUrl)), savePath);
thread.start();
threads[i] = thread;
}
// 等待所有的线程下载完成
for (int i = 0; i < threadNum; i++) {
threads[i].join();
}
System.out.println("文件下载完成");
} catch (Exception e) {
e.printStackTrace();
System.out.println("下载文件出现异常");
}
}
// 根据图片URL获取图片名称
public static String getFileName(String imageUrl) {
int index = imageUrl.lastIndexOf("/");
return imageUrl.substring(index + 1);
}
// 下载线程
public static class FileDownloadThread extends Thread {
private URL url; // 下载链接
private int start; // 线程下载开始位置
private int end; // 线程下载结束位置
private File file; // 本地保存的文件
private String savePath; // 文件保存目录
public FileDownloadThread(URL url, int start, int end, File file, String savePath) {
this.url = url;
this.start = start;
this.end = end;
this.file = file;
this.savePath = savePath;
if (!file.exists()) {
try {
FileOutputStream out = new FileOutputStream(file);
byte[] buf = new byte[end - start + 1];
out.write(buf);
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
public void run() {
try {
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Range", "bytes=" + start + "-" + end);
InputStream in = connection.getInputStream();
byte[] buf = new byte[1024];
int len = 0;
RandomAccessFile out = new RandomAccessFile(file, "rw");
out.seek(start);
while ((len = in.read(buf)) != -1) {
out.write(buf, 0, len);
}
out.close();
in.close();
connection.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
以上就是Java多线程下载的实现方法和示例。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java多线程下载实例详解 - Python技术站