多线程下载
public class MultiThreadDownloader {
private URL url; // 目标地址
private File file; // 本地文件
private long threadLen; // 每个线程下载多少
private static final int THREAD_AMOUNT = 3; // 线程数
private static final String DIR_PATH = "F:/Download"; // 下载目录
public MultiThreadDownloader(String address) throws IOException {
// 记住下载地址
url = new URL(address);
// 截取地址中的文件名, 创建本地文件
file = new File(DIR_PATH, address.substring(address.lastIndexOf("/") + 1));
}
public void download() throws IOException {
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(3000);
// 获取文件总长度
long totalLen = conn.getContentLength();
// 计算每个线程要下载的长度
// 总长度 如果能整除 线程数, 每条线程下载的长度就是 总长度 / 线程数
// 总长度 如果不能整除 线程数, 那么每条线程下载长度就是 总长度 / 线程数 + 1
threadLen = (totalLen + THREAD_AMOUNT - 1) / THREAD_AMOUNT;
// 在本地创建一个和服务端大小相同的文件
RandomAccessFile raf = new RandomAccessFile(file, "rw");
// 设置文件的大小, 写入了若干个0
raf.setLength(totalLen);
raf.close();
// 按照线程数循环
for (int i = 0; i < THREAD_AMOUNT; i++) {
// 开启线程, 每个线程将会下载一部分数据到本地文件中
new DownloadThread(i).start();
}
}
private class DownloadThread extends Thread {
// 用来标记当前线程是下载任务中的第几个线程
private int id;
public DownloadThread(int id) {
this.id = id;
}
public void run() {
// 从临时文件读取当前线程已完成的进度
long start = id * threadLen;
long end = id * threadLen + threadLen - 1;
System.out.println("线程" + id + ": " + start + "-" + end);
try {
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(3000);
// 设置当前线程下载的范围(start和end都包含)
conn.setRequestProperty("Range", "bytes=" + start + "-" + end);
InputStream in = conn.getInputStream();
// 随机读写文件, 用来向本地文件写出
RandomAccessFile raf = new RandomAccessFile(file, "rw");
// 设置保存数据的位置
raf.seek(start);
// 每次拷贝100KB
byte[] buffer = new byte[1024 * 100];
int len;
while ((len = in.read(buffer)) != -1) {
// 从服务端读取数据, 写到本地文件
raf.write(buffer, 0, len);
}
raf.close();
System.out.println("线程" + id + "下载完毕");
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws IOException {
new MultiThreadDownloader("http://192.168.1.240:8080/14.Web/android-sdk_r17-windows.zip").download();
}
}
断点下载
public class BreakpointDownloader {
// 下载目录
private static final String DIR_PATH = "F:/Download";
// 总线程数
private static final int THREAD_AMOUNT = 3;
// 目标下载地址
private URL url;
// 本地文件
private File dataFile;
// 用来存储每个线程下载的进度的临时文件
private File tempFile;
// 每个线程要下载的长度
private long threadLen;
// 总共完成了多少
private long totalFinish;
// 服务端文件总长度
private long totalLen;
// 用来记录开始下载时的时间
private long begin;
public BreakpointDownloader(String address) throws IOException {
url = new URL(address);
dataFile = new File(DIR_PATH, address.substring(address.lastIndexOf("/") + 1));
tempFile = new File(dataFile.getAbsolutePath() + ".temp");
}
public void download() throws IOException {
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(3000);
totalLen = conn.getContentLength();
threadLen = (totalLen + THREAD_AMOUNT - 1) / THREAD_AMOUNT;
if (!dataFile.exists()) {
RandomAccessFile raf = new RandomAccessFile(dataFile, "rws");
raf.setLength(totalLen);
raf.close();
}
if (!tempFile.exists()) {
RandomAccessFile raf = new RandomAccessFile(tempFile, "rws");
for (int i = 0; i < THREAD_AMOUNT; i++)
raf.writeLong(0);
raf.close();
}
for (int i = 0; i < THREAD_AMOUNT; i++) {
new DownloadThread(i).start();
}
// 记录开始时间
begin = System.currentTimeMillis();
}
private class DownloadThread extends Thread {
// 用来标记当前线程是下载任务中的第几个线程
private int id;
public DownloadThread(int id) {
this.id = id;
}
public void run() {
try {
RandomAccessFile tempRaf = new RandomAccessFile(tempFile, "rws");
tempRaf.seek(id * 8);
long threadFinish = tempRaf.readLong();
synchronized(BreakpointDownloader.this) {
totalFinish += threadFinish;
}
long start = id * threadLen + threadFinish;
long end = id * threadLen + threadLen - 1;
System.out.println("线程" + id + ": " + start + "-" + end);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(3000);
conn.setRequestProperty("Range", "bytes=" + start + "-" + end);
InputStream in = conn.getInputStream();
RandomAccessFile dataRaf = new RandomAccessFile(dataFile, "rws");
dataRaf.seek(start);
byte[] buffer = new byte[1024 * 100];
int len;
while ((len = in.read(buffer)) != -1) {
dataRaf.write(buffer, 0, len);
threadFinish += len;
tempRaf.seek(id * 8);
tempRaf.writeLong(threadFinish);
synchronized(BreakpointDownloader.this) {
totalFinish += len;
}
}
dataRaf.close();
tempRaf.close();
System.out.println("线程" + id + "下载完毕");
// 如果已完成长度等于服务端文件长度(代表下载完成)
if (totalFinish == totalLen) {
System.out.println("下载完成, 耗时: " + (System.currentTimeMillis() - begin));
// 删除临时文件
tempFile.delete();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws IOException {
new BreakpointDownloader("http://192.168.1.240:8080/14.Web/android-sdk_r17-windows.zip").download();
}
}