- 一:实现基本的下载的功能
- 代码实现:
- 常量类:
- http相关工具类
- 日志工具类
- 下载器
- 测试类
- 二:展示下载信息
- 代码实现
- 常量类
- 文件类
- http相关工具类
- 日志工具类
- 展示下载信息
- 下载器
- 测试类
- 三:使用多线程分段下载
- 代码实现
- 常量类
- 文件类
- http相关工具类
- 日志工具类
- 展示下载信息
- 分块载任务
- 下载器
- 测试类
- 四:分段合并下载
- 代码实现:
- 常量类
- 文件类
- http相关工具类
- 日志工具类
- 分块载任务
- 展示下载信息
- 下载器
- 测试类
git链接:https://gitee.com/zhongbai111/multithreaded-block-download.git
public class Constant {
public static final String PATH = "E:\mytest\";
}
http相关工具类
public class HttpUtils {
public static HttpURLConnection getHttpURLConnection(String url) throws IOException {
URL httpUrl = new URL(url);
HttpURLConnection httpURLConnection = (HttpURLConnection)httpUrl.openConnection();
//向文件所在的服务器发送标识信息
httpURLConnection.setRequestProperty("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1");
return httpURLConnection;
}
public static String getHttpFileName(String url) {
int index = url.lastIndexOf("/");
return url.substring(index + 1);
}
}
日志工具类
public class LogUtils {
public static void info(String msg, Object... args) {
print(msg,"-info-",args);
}
public static void error(String msg, Object... args) {
print(msg,"-error-",args);
}
private static void print(String msg, String level, Object... args) {
if (args != null && args.length > 0) {
msg = String.format(msg.replace("{}", "%s"), args);
}
String name = Thread.currentThread().getName();
System.out.println(LocalTime.now().format(DateTimeFormatter.ofPattern("hh:mm:ss")) + " " + name + level + msg);
}
}
下载器
public class Downloader {
public void download(String url) {
//获取文件名
String httpFileName = HttpUtils.getHttpFileName(url);
//文件下载路径
httpFileName = Constant.PATH + httpFileName;
//获取连接对象
HttpURLConnection httpURLConnection = null;
try {
httpURLConnection = HttpUtils.getHttpURLConnection(url);
} catch (IOException e) {
e.printStackTrace();
}
try (
InputStream input = httpURLConnection.getInputStream();
BufferedInputStream bis = new BufferedInputStream(input);
FileOutputStream fos = new FileOutputStream(httpFileName);
BufferedOutputStream bos = new BufferedOutputStream(fos)
) {
int len = -1;
while ((len = bis.read()) != -1) {
bos.write(len);
}
} catch (FileNotFoundException e) {
LogUtils.error("下载的文件不存在{}",url);//下载的文件不存在abc
} catch (Exception e) {
LogUtils.error("下载失败");
} finally {
//关闭连接对象
if (httpURLConnection != null) {
httpURLConnection.disconnect();
}
}
}
}
测试类
public class Main {
public static void main(String[] args) {
//下载地址
String url = null;
if (args == null || args.length == 0) {
for (; ; ) {
LogUtils.info("请输入下载地址");
Scanner scanner = new Scanner(System.in);
url = scanner.next();
if (url != null) {
break;
}
}
}else {
url = args[0];
}
Downloader downloader = new Downloader();
downloader.download(url);
}
}
二:展示下载信息
代码实现
常量类
public class Constant {
public static final String PATH = "E:\mytest\";
public static final double MB = 1024d * 1024d;
public static final int BYTE_SIZE = 1024 * 100;
}
文件类
public class FileUtils {
public static long getFileContentLength(String path) {
File file = new File(path);
return file.exists() && file.isFile() ? file.length() : 0;
}
}
http相关工具类
public class HttpUtils {
public static HttpURLConnection getHttpURLConnection(String url) throws IOException {
URL httpUrl = new URL(url);
HttpURLConnection httpURLConnection = (HttpURLConnection)httpUrl.openConnection();
//向文件所在的服务器发送标识信息
httpURLConnection.setRequestProperty("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1");
return httpURLConnection;
}
public static String getHttpFileName(String url) {
int index = url.lastIndexOf("/");
return url.substring(index + 1);
}
}
日志工具类
public class LogUtils {
public static void info(String msg, Object... args) {
print(msg,"-info-",args);
}
public static void error(String msg, Object... args) {
print(msg,"-error-",args);
}
private static void print(String msg, String level, Object... args) {
if (args != null && args.length > 0) {
msg = String.format(msg.replace("{}", "%s"), args);
}
String name = Thread.currentThread().getName();
System.out.println(LocalTime.now().format(DateTimeFormatter.ofPattern("hh:mm:ss")) + " " + name + level + msg);
}
}
展示下载信息
public class DownloadInfoThread implements Runnable {
//下载文件总大小
private long httpFileContentLength;
//本地已下载文件的大小,
public double finishedSize;
//本次累计下载的大小
public volatile double downSize;
//前一次下载的大小
public double prevSize;
public DownloadInfoThread(long httpFileContentLength) {
this.httpFileContentLength = httpFileContentLength;
}
@Override
public void run() {
//计算文件总大小 单位:mb
String httpFileSize = String.format("%.2f", httpFileContentLength / Constant.MB);
//计算每秒下载速度 kb
int speed = (int)((downSize - prevSize) / 1024d);
prevSize = downSize;
//剩余文件的大小
double remainSize = httpFileContentLength - finishedSize - downSize;
//计算剩余时间
String remainTime = String.format("%.1f", remainSize / 1024d / speed);
if ("Infinity".equalsIgnoreCase(remainTime)) {
remainTime = "-";
}
//已下载大小
String currentFileSize = String.format("%.2f", (downSize - finishedSize) / Constant.MB);
String downInfo = String.format("已下载 %smb/%smb,速度 %skb/s,剩余时间 %ss",
currentFileSize, httpFileSize, speed, remainTime);
System.out.print("r");
System.out.print(downInfo);
}
}
下载器
public class Downloader {
public ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
public void download(String url) {
//获取文件名
String httpFileName = HttpUtils.getHttpFileName(url);
//文件下载路径
httpFileName = Constant.PATH + httpFileName;
//获取本地文件的大小
long localFileLength = FileUtils.getFileContentLength(httpFileName);
//获取连接对象
HttpURLConnection httpURLConnection = null;
DownloadInfoThread downloadInfoThread = null;
try {
httpURLConnection = HttpUtils.getHttpURLConnection(url);
//获取下载文件的总大小
int contentLength = httpURLConnection.getContentLength();
//判断文件是否已下载过
if (localFileLength >= contentLength) {
LogUtils.info("{}已下载完毕,无需重新下载",httpFileName);
return;
}
//创建获取下载信息的任务对象
downloadInfoThread = new DownloadInfoThread(contentLength);
//将任务交给线程执行,每隔1秒执行一次
scheduledExecutorService.scheduleAtFixedRate(downloadInfoThread,1,1, TimeUnit.SECONDS);
} catch (IOException e) {
e.printStackTrace();
}
try (
InputStream input = httpURLConnection.getInputStream();
BufferedInputStream bis = new BufferedInputStream(input);
FileOutputStream fos = new FileOutputStream(httpFileName);
BufferedOutputStream bos = new BufferedOutputStream(fos)
) {
int len = -1;
byte[] buffer = new byte[Constant.BYTE_SIZE];
while ((len = bis.read(buffer)) != -1) {
downloadInfoThread.downSize += len;
bos.write(buffer,0,len);
}
} catch (FileNotFoundException e) {
LogUtils.error("下载的文件不存在{}",url);//下载的文件不存在abc
} catch (Exception e) {
LogUtils.error("下载失败");
} finally {
System.out.print("r");
System.out.print("下载完成");
//关闭连接对象
if (httpURLConnection != null) {
httpURLConnection.disconnect();
}
//关闭
scheduledExecutorService.shutdownNow();
}
}
}
测试类
public class Main {
public static void main(String[] args) {
//下载地址
String url = null;
if (args == null || args.length == 0) {
for (; ; ) {
LogUtils.info("请输入下载地址");
Scanner scanner = new Scanner(System.in);
url = scanner.next();
if (url != null) {
break;
}
}
}else {
url = args[0];
}
Downloader downloader = new Downloader();
downloader.download(url);
}
}
三:使用多线程分段下载
代码实现
常量类
public class Constant {
public static final String PATH = "E:\mytest\";
public static final double MB = 1024d * 1024d;
public static final int BYTE_SIZE = 1024 * 100;
//线程数量
public static final int THREAD_NUM = 5;
}
文件类
public class FileUtils {
public static long getFileContentLength(String path) {
File file = new File(path);
return file.exists() && file.isFile() ? file.length() : 0;
}
}
http相关工具类
public class HttpUtils {
public static long getHttpFileContentLength(String url) throws IOException {
int contentLength;
HttpURLConnection httpURLConnection = null;
try {
httpURLConnection = getHttpURLConnection(url);
contentLength = httpURLConnection.getContentLength();
} finally {
if (httpURLConnection != null) {
httpURLConnection.disconnect();
}
}
return contentLength;
}
public static HttpURLConnection getHttpURLConnection(String url, long startPos, long endPos) throws IOException {
HttpURLConnection httpURLConnection = getHttpURLConnection(url);
LogUtils.info("下载的区间是:{}-{}",startPos,endPos);
if (endPos != 0) {
httpURLConnection.setRequestProperty("RANGE","bytes="+startPos + "-" + endPos);
}else {
httpURLConnection.setRequestProperty("RANGE","bytes="+startPos + "-");
}
return httpURLConnection;
}
public static HttpURLConnection getHttpURLConnection(String url) throws IOException {
URL httpUrl = new URL(url);
HttpURLConnection httpURLConnection = (HttpURLConnection)httpUrl.openConnection();
//向文件所在的服务器发送标识信息
httpURLConnection.setRequestProperty("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1");
return httpURLConnection;
}
public static String getHttpFileName(String url) {
int index = url.lastIndexOf("/");
return url.substring(index + 1);
}
}
日志工具类
public class LogUtils {
public static void info(String msg, Object... args) {
print(msg,"-info-",args);
}
public static void error(String msg, Object... args) {
print(msg,"-error-",args);
}
private static void print(String msg, String level, Object... args) {
if (args != null && args.length > 0) {
msg = String.format(msg.replace("{}", "%s"), args);
}
String name = Thread.currentThread().getName();
System.out.println(LocalTime.now().format(DateTimeFormatter.ofPattern("hh:mm:ss")) + " " + name + level + msg);
}
}
展示下载信息
public class DownloadInfoThread implements Runnable {
//下载文件总大小
private long httpFileContentLength;
//本地已下载文件的大小,
public static LongAdder finishedSize = new LongAdder();
//本次累计下载的大小
public static volatile LongAdder downSize = new LongAdder();
//前一次下载的大小
public double prevSize;
public DownloadInfoThread(long httpFileContentLength) {
this.httpFileContentLength = httpFileContentLength;
}
@Override
public void run() {
//计算文件总大小 单位:mb
String httpFileSize = String.format("%.2f", httpFileContentLength / Constant.MB);
//计算每秒下载速度 kb
int speed = (int)((downSize.doublevalue() - prevSize) / 1024d);
prevSize = downSize.doublevalue();
//剩余文件的大小
double remainSize = httpFileContentLength - finishedSize.doublevalue() - downSize.doublevalue();
//计算剩余时间
String remainTime = String.format("%.1f", remainSize / 1024d / speed);
if ("Infinity".equalsIgnoreCase(remainTime)) {
remainTime = "-";
}
//已下载大小
String currentFileSize = String.format("%.2f", (downSize.doublevalue() - finishedSize.doublevalue()) / Constant.MB);
String downInfo = String.format("已下载 %smb/%smb,速度 %skb/s,剩余时间 %ss",
currentFileSize, httpFileSize, speed, remainTime);
System.out.print("r");
System.out.print(downInfo);
}
}
分块载任务
public class DownloaderTask implements Callable下载器{ private String url; //下载的起始位置 private long startPos; //下载的结束位置 private long endPos; //标识当前是哪一部分 private int part; public DownloaderTask(String url, long startPos, long endPos, int part) { this.url = url; this.startPos = startPos; this.endPos = endPos; this.part = part; } @Override public Boolean call() throws Exception { //获取文件名 String httpFileName = HttpUtils.getHttpFileName(url); //分块的文件名 httpFileName = httpFileName + ".temp" + part; //下载路径 httpFileName = Constant.PATH + httpFileName; //获取分块下载的连接 HttpURLConnection httpURLConnection = HttpUtils.getHttpURLConnection(url, startPos, endPos); try ( InputStream input = httpURLConnection.getInputStream(); BufferedInputStream bis = new BufferedInputStream(input); RandomAccessFile accessFile = new RandomAccessFile(httpFileName, "rw") ) { byte[] buffer = new byte[Constant.BYTE_SIZE]; int len = -1; //循环读取数据 while ((len = bis.read(buffer)) != -1) { //1秒内下载数据之和, 通过原子类进行操作 DownloadInfoThread.downSize.add(len); accessFile.write(buffer,0,len); } } catch (FileNotFoundException e) { LogUtils.error("下载文件不存在{}", url); return false; } catch (Exception e) { LogUtils.error("下载出现异常"); return false; } finally { httpURLConnection.disconnect(); } return true; } }
public class Downloader {
public ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
//线程池对象
public ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(Constant.THREAD_NUM, Constant.THREAD_NUM, 0, TimeUnit.SECONDS, new ArrayBlockingQueue<>(Constant.THREAD_NUM));
public void download(String url) {
//获取文件名
String httpFileName = HttpUtils.getHttpFileName(url);
//文件下载路径
httpFileName = Constant.PATH + httpFileName;
//获取本地文件的大小
long localFileLength = FileUtils.getFileContentLength(httpFileName);
//获取连接对象
HttpURLConnection httpURLConnection = null;
DownloadInfoThread downloadInfoThread = null;
try {
httpURLConnection = HttpUtils.getHttpURLConnection(url);
//获取下载文件的总大小
int contentLength = httpURLConnection.getContentLength();
//判断文件是否已下载过
if (localFileLength >= contentLength) {
LogUtils.info("{}已下载完毕,无需重新下载",httpFileName);
return;
}
//创建获取下载信息的任务对象
downloadInfoThread = new DownloadInfoThread(contentLength);
//将任务交给线程执行,每隔1秒执行一次
scheduledExecutorService.scheduleAtFixedRate(downloadInfoThread,1,1, TimeUnit.SECONDS);
//切分任务
ArrayList list = new ArrayList<>();
spilt(url, list);
list.forEach(future -> {
try {
future.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
});
} catch (IOException e) {
e.printStackTrace();
} finally {
System.out.print("r");
System.out.print("下载完成");
//关闭连接对象
if (httpURLConnection != null) {
httpURLConnection.disconnect();
}
//关闭
scheduledExecutorService.shutdownNow();
//关闭线程池
poolExecutor.shutdown();
}
}
public void spilt(String url, ArrayList futureList) {
try {
//获取下载文件大小
long contentLength = HttpUtils.getHttpFileContentLength(url);
//计算切分后的文件大小
long size = contentLength / Constant.THREAD_NUM;
//计算分块个数
for (int i = 0; i < Constant.THREAD_NUM; i++) {
//计算下载起始位置
long startPos = i * size;
//计算结束位置
long endPos;
if (i == Constant.THREAD_NUM - 1) {
//下载最后一块,下载剩余的部分
endPos = 0;
}else {
endPos = startPos + size;
}
//如果不是第一块,起始位置要+1
if (startPos != 0) {
startPos++;
}
//创建任务对象
DownloaderTask downloaderTask = new DownloaderTask(url, startPos, endPos,i);
//将任务提交到线程池中
Future future = poolExecutor.submit(downloaderTask);
futureList.add(future);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
测试类
public class Main {
public static void main(String[] args) {
//下载地址
String url = null;
if (args == null || args.length == 0) {
for (; ; ) {
LogUtils.info("请输入下载地址");
Scanner scanner = new Scanner(System.in);
url = scanner.next();
if (url != null) {
break;
}
}
}else {
url = args[0];
}
Downloader downloader = new Downloader();
downloader.download(url);
}
}
四:分段合并下载
public class Constant {
public static final String PATH = "E:\mytest\";
public static final double MB = 1024d * 1024d;
public static final int BYTE_SIZE = 1024 * 100;
//线程数量
public static final int THREAD_NUM = 5;
}
文件类
public class FileUtils {
public static long getFileContentLength(String path) {
File file = new File(path);
return file.exists() && file.isFile() ? file.length() : 0;
}
}
http相关工具类
public class HttpUtils {
public static long getHttpFileContentLength(String url) throws IOException {
int contentLength;
HttpURLConnection httpURLConnection = null;
try {
httpURLConnection = getHttpURLConnection(url);
contentLength = httpURLConnection.getContentLength();
} finally {
if (httpURLConnection != null) {
httpURLConnection.disconnect();
}
}
return contentLength;
}
public static HttpURLConnection getHttpURLConnection(String url, long startPos, long endPos) throws IOException {
HttpURLConnection httpURLConnection = getHttpURLConnection(url);
LogUtils.info("下载的区间是:{}-{}",startPos,endPos);
if (endPos != 0) {
httpURLConnection.setRequestProperty("RANGE","bytes="+startPos + "-" + endPos);
}else {
httpURLConnection.setRequestProperty("RANGE","bytes="+startPos + "-");
}
return httpURLConnection;
}
public static HttpURLConnection getHttpURLConnection(String url) throws IOException {
URL httpUrl = new URL(url);
HttpURLConnection httpURLConnection = (HttpURLConnection)httpUrl.openConnection();
//向文件所在的服务器发送标识信息
httpURLConnection.setRequestProperty("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1");
return httpURLConnection;
}
public static String getHttpFileName(String url) {
int index = url.lastIndexOf("/");
return url.substring(index + 1);
}
}
日志工具类
public class LogUtils {
public static void info(String msg, Object... args) {
print(msg,"-info-",args);
}
public static void error(String msg, Object... args) {
print(msg,"-error-",args);
}
private static void print(String msg, String level, Object... args) {
if (args != null && args.length > 0) {
msg = String.format(msg.replace("{}", "%s"), args);
}
String name = Thread.currentThread().getName();
System.out.println(LocalTime.now().format(DateTimeFormatter.ofPattern("hh:mm:ss")) + " " + name + level + msg);
}
}
分块载任务
public class DownloaderTask implements Callable展示下载信息{ private String url; //下载的起始位置 private long startPos; //下载的结束位置 private long endPos; //标识当前是哪一部分 private int part; private CountDownLatch countDownLatch; public DownloaderTask(String url, long startPos, long endPos, int part, CountDownLatch countDownLatch) { this.url = url; this.startPos = startPos; this.endPos = endPos; this.part = part; this.countDownLatch = countDownLatch; } @Override public Boolean call() throws Exception { //获取文件名 String httpFileName = HttpUtils.getHttpFileName(url); //分块的文件名 httpFileName = httpFileName + ".temp" + part; //下载路径 httpFileName = Constant.PATH + httpFileName; //获取分块下载的连接 HttpURLConnection httpURLConnection = HttpUtils.getHttpURLConnection(url, startPos, endPos); try ( InputStream input = httpURLConnection.getInputStream(); BufferedInputStream bis = new BufferedInputStream(input); RandomAccessFile accessFile = new RandomAccessFile(httpFileName, "rw") ) { byte[] buffer = new byte[Constant.BYTE_SIZE]; int len = -1; //循环读取数据 while ((len = bis.read(buffer)) != -1) { //1秒内下载数据之和, 通过原子类进行操作 DownloadInfoThread.downSize.add(len); accessFile.write(buffer,0,len); } } catch (FileNotFoundException e) { LogUtils.error("下载文件不存在{}", url); return false; } catch (Exception e) { LogUtils.error("下载出现异常"); return false; } finally { httpURLConnection.disconnect(); //如果减到了0,则会唤醒所有等待在这个latch上的线程。 countDownLatch.countDown(); } return true; } }
public class DownloadInfoThread implements Runnable {
//下载文件总大小
private long httpFileContentLength;
//本地已下载文件的大小,
public static LongAdder finishedSize = new LongAdder();
//本次累计下载的大小 LongAdder保证共享数据的原子性
public static volatile LongAdder downSize = new LongAdder();
//前一次下载的大小
public double prevSize;
public DownloadInfoThread(long httpFileContentLength) {
this.httpFileContentLength = httpFileContentLength;
}
@Override
public void run() {
//计算文件总大小 单位:mb
String httpFileSize = String.format("%.2f", httpFileContentLength / Constant.MB);
//计算每秒下载速度 kb
int speed = (int)((downSize.doublevalue() - prevSize) / 1024d);
prevSize = downSize.doublevalue();
//剩余文件的大小
double remainSize = httpFileContentLength - finishedSize.doublevalue() - downSize.doublevalue();
//计算剩余时间
String remainTime = String.format("%.1f", remainSize / 1024d / speed);
if ("Infinity".equalsIgnoreCase(remainTime)) {
remainTime = "-";
}
//已下载大小
String currentFileSize = String.format("%.2f", (downSize.doublevalue() - finishedSize.doublevalue()) / Constant.MB);
String downInfo = String.format("已下载 %smb/%smb,速度 %skb/s,剩余时间 %ss",
currentFileSize, httpFileSize, speed, remainTime);
System.out.print("r");
System.out.print(downInfo);
}
}
下载器
public class Downloader {
public ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
//线程池对象
public ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(Constant.THREAD_NUM, Constant.THREAD_NUM, 0, TimeUnit.SECONDS, new ArrayBlockingQueue<>(Constant.THREAD_NUM));
private CountDownLatch countDownLatch = new CountDownLatch(Constant.THREAD_NUM);
public void download(String url) {
//获取文件名
String httpFileName = HttpUtils.getHttpFileName(url);
//文件下载路径
httpFileName = Constant.PATH + httpFileName;
//获取本地文件的大小
long localFileLength = FileUtils.getFileContentLength(httpFileName);
//获取连接对象
HttpURLConnection httpURLConnection = null;
DownloadInfoThread downloadInfoThread = null;
try {
httpURLConnection = HttpUtils.getHttpURLConnection(url);
//获取下载文件的总大小
int contentLength = httpURLConnection.getContentLength();
//判断文件是否已下载过
if (localFileLength >= contentLength) {
LogUtils.info("{}已下载完毕,无需重新下载",httpFileName);
return;
}
//创建获取下载信息的任务对象
downloadInfoThread = new DownloadInfoThread(contentLength);
//将任务交给线程执行,每隔1秒执行一次
scheduledExecutorService.scheduleAtFixedRate(downloadInfoThread,1,1, TimeUnit.SECONDS);
//切分任务
ArrayList list = new ArrayList<>();
spilt(url, list);
//使当前线程进入同步队列进行等待,直到latch的值被减到0或者当前线程被中断,当前线程就会被唤醒。
countDownLatch.await();
//合并文件
if (merge(httpFileName)) {
//清除临时文件
clearTemp(httpFileName);
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.print("r");
System.out.print("下载完成");
//关闭连接对象
if (httpURLConnection != null) {
httpURLConnection.disconnect();
}
//关闭
scheduledExecutorService.shutdownNow();
//关闭线程池
poolExecutor.shutdown();
}
}
public void spilt(String url, ArrayList futureList) {
try {
//获取下载文件大小
long contentLength = HttpUtils.getHttpFileContentLength(url);
//计算切分后的文件大小
long size = contentLength / Constant.THREAD_NUM;
//计算分块个数
for (int i = 0; i < Constant.THREAD_NUM; i++) {
//计算下载起始位置
long startPos = i * size;
//计算结束位置
long endPos;
if (i == Constant.THREAD_NUM - 1) {
//下载最后一块,下载剩余的部分
endPos = 0;
}else {
endPos = startPos + size;
}
//如果不是第一块,起始位置要+1
if (startPos != 0) {
startPos++;
}
//创建任务对象
DownloaderTask downloaderTask = new DownloaderTask(url, startPos, endPos,i,countDownLatch);
//将任务提交到线程池中
Future future = poolExecutor.submit(downloaderTask);
futureList.add(future);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public boolean merge(String fileName) {
LogUtils.info("开始合并文件{}", fileName);
byte[] buffer = new byte[Constant.BYTE_SIZE];
int len = -1;
try (RandomAccessFile accessFile = new RandomAccessFile(fileName, "rw")) {
for (int i = 0; i < Constant.THREAD_NUM ; i++) {
try(BufferedInputStream bis = new BufferedInputStream(new FileInputStream(fileName + ".temp" + i))) {
while ((len = bis.read(buffer)) != -1) {
accessFile.write(buffer,0,len);
}
}
}
LogUtils.info("文件合并完毕{}" + fileName);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
public boolean clearTemp(String fileName) {
for (int i = 0; i < Constant.THREAD_NUM; i++) {
File file = new File(fileName + ".temp" + i);
file.delete();
}
return true;
}
}
测试类
public class Main {
public static void main(String[] args) {
//下载地址
String url = null;
if (args == null || args.length == 0) {
for (; ; ) {
LogUtils.info("请输入下载地址");
Scanner scanner = new Scanner(System.in);
url = scanner.next();
if (url != null) {
break;
}
}
}else {
url = args[0];
}
Downloader downloader = new Downloader();
downloader.download(url);
}
}



