DownloadUtil 自定义工具类通过URL进行多线程下载
package com.jtc;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Date;
/**
* 通过 URL 多线程下载文件
* URL 对象提供的openStream() ,再通过它获取 URL 资源的 InputStream。
*/
public class DownloadUtil {
public String down(final String href) throws InterruptedException, Exception {
// 获取当前时间
long begin_time = new Date().getTime();
URL url = new URL(href);
URLConnection conn = url.openConnection();
//获取该URL的资源名,然后获取文件名
String fileName = url.getFile();
fileName = fileName.substring(fileName.lastIndexOf("/"));
System.out.println("开始下载>>>");
// 获取文件大小
final int fileSize = conn.getContentLength();
System.out.println("文件总共大小:" + fileSize + "字节");
// 设置分块大小 1MB
final int blockSize = 1024 * 1024;
// 根据文件大小得出文件 分块的数量,即后面设置的线程的数量
int blockNum = fileSize / blockSize;
if ((fileSize % blockSize) != 0) {
blockNum += 1;
}
System.out.println("分块数->线程数:" + blockNum);
Thread[] threads = new Thread[blockNum];
for (int i = 0; i < blockNum; i++) {
// 匿名函数对象需要用到的变量
final int index = i;
final int finalBlockNum = blockNum;
final String finalFileName = fileName;
final String targetFile = "E:\\Down\\";
// 创建一个线程
threads[i] = new Thread() {
public void run() {
URL url = null;
try {
url = new URL(href);
} catch (MalformedURLException e) {
e.printStackTrace();
}
try {
// 重新获取连接
URLConnection conn = url.openConnection();
// 重新获取流,输入流,写入内存
InputStream in = conn.getInputStream();
// 定义起始和结束点
int beginPoint = 0, endPoint = 0;
System.out.print("第" + (index + 1) + "块文件:");
beginPoint = index * blockSize;
// 判断结束点
if (index < finalBlockNum - 1) {
endPoint = beginPoint + blockSize;
} else {
endPoint = fileSize;
}
System.out.println("起始字节数:" + beginPoint + ",结束字节数:" + endPoint);
// 将下载的文件存储到一个文件夹中
//当该文件夹不存在时,则新建
File filePath = new File(targetFile);
if (!filePath.exists()) {
filePath.mkdirs();
}
FileOutputStream fos = new FileOutputStream(new File(targetFile, finalFileName + "_" + (index + 1)));
// 跳过 beginPoint个字节进行读取
in.skip(beginPoint);
byte[] buffer = new byte[1024];
int count;
// 定义当前下载进度
int process = beginPoint;
// 当前进度必须小于结束字节数
while (process < endPoint) {
count = in.read(buffer);
// 判断是否读到最后一块
if (process + count >= endPoint) {
count = endPoint - process;
process = endPoint;
} else {
// 计算当前进度
process += count;
}
// 保存文件流,count 本次写入的量
fos.write(buffer, 0, count);
}
fos.close();
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
};
threads[i].start();
}
// 当所有线程都结束时才开始文件的合并
for (Thread t : threads) {
// 让主线程等待(WAITING状态),一直等到 t线程 不再活动为止。
t.join();
}
// 若该文件夹不存在,则创建一个文件夹
File filePath = new File("E:/Down/final/");
if (!filePath.exists()) {
filePath.mkdirs();
}
// 定义文件输出流
FileOutputStream fos = new FileOutputStream("E:/Down/final/" + fileName);
for (int i = 0; i < blockNum; i++) {
FileInputStream fis = new FileInputStream("E:\\Down\\" + fileName + "_" + (i + 1));
byte[] buffer = new byte[1024];
int count;
try {
while ((count = fis.read(buffer)) > 0) {
fos.write(buffer, 0, count);
}
} catch (IOException e) {
e.printStackTrace();
}
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
long end_time = new Date().getTime();
long seconds = (end_time - begin_time) / 1000;
long minutes = seconds / 60;
long second = seconds % 60;
System.out.println("下载完成,用时:" + minutes + "分" + second + "秒");
return fileName;
}
public static void main(String[] args) {
String str = "https://www.baidu.com/img/pc_79bff59263430e2e42693b50cf376490.png";
DownloadUtil downloadURLFile = new DownloadUtil();
try {
downloadURLFile.down(str);
} catch (Exception e) {
e.printStackTrace();
}
}
}
随机选取百度首页的图片进行下载,结果:
开始下载>>>
文件总共大小:112921字节
分块数->线程数:1
第1块文件:起始字节数:0,结束字节数:112921
下载完成,用时:0分2秒
Process finished with exit code 0