Java实现多线程下载文件
2018-01-16 18:57
513 查看
原文地址:https://blog.dubby.cn/detail.html?id=9090
下载下来后,改名为
其中有三个参数:
下载的URL,必填
下载到目标目录,选填,如果不指定,下载到当前目前下
开启的线程数,选填,默认是10个线程
测试结果:
1.基本原理
先使用head方法查询得到对应文件的
Content-Length,然后拆分成多个部分,交由多个线程去处理,使用
"Range", "bytes=" + start + "-" + end这个header来指定下载文件的哪个部分。
2.代码实现
为了方便展示,我是用了一个类来实现,其余都是内部类/** * Created by yangzheng03 on 2018/1/16. * https://www.dubby.cn/ */ public class DownloadTool { private static String prefix = String.valueOf(System.currentTimeMillis()); private static String path = ""; public static void main(String[] args) { long startTimestamp = System.currentTimeMillis(); if (args == null || args.length < 1) { System.out.println("please input the file url."); return; } final String urlString = args[0]; if (args.length >= 2) { path = args[1]; } int number = 10; if (args.length >= 3) { number = Integer.parseInt(args[2]); } System.out.println("Download started, url is \"" + urlString + "\""); ExecutorService threadPool = Executors.newFixedThreadPool(number); try { URL url = new URL(urlString); HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection(); httpURLConnection.setRequestMethod("HEAD"); String contentLengthStr = httpURLConnection.getHeaderField("Content-Length"); long contentLength = Long.parseLong(contentLengthStr); if (contentLength > 1024 * 1024) { System.out.println("Content-Length\t" + (contentLength / 1024 / 1024) + "MB"); } else if (contentLength > 1024) { System.out.println("Content-Length\t" + (contentLength / 1024) + "KB"); } else { System.out.println("Content-Length\t" + (contentLength) + "B"); } long tempLength = contentLength / number; long start = 0, end = -1; Map<Integer, Future<DownloadTemp>> futureMap = new HashMap<>(number); for (int i = 0; i < number; ++i) { start = end + 1; end = end + tempLength; if (i == number - 1) { end = contentLength; } System.out.println("start:\t" + start + "\tend:\t" + end); DownloadThread thread = new DownloadThread(i, start, end, urlString); futureMap.put(i, threadPool.submit(thread)); } System.out.println(); String filename = urlString.substring(urlString.lastIndexOf("/") + 1); if (!path.equals("")) { filename = path + "/" + filename; } RandomAccessFile resultFile = new RandomAccessFile(filename, "rw"); for (int i = 0; i < number; ++i) { Future<DownloadTemp> future = futureMap.get(i); DownloadTemp temp = future.get(); RandomAccessFile tempFile = new RandomAccessFile(temp.filename, "r"); tempFile.getChannel().transferTo(0, tempFile.length(), resultFile.getChannel()); } threadPool.shutdown(); } catch (Exception e) { e.printStackTrace(); } long completedTimestamp = System.currentTimeMillis(); System.out.println(); System.out.println("cost " + (completedTimestamp - startTimestamp) / 1000 + "s"); } private static class DownloadThread implements Callable<DownloadTemp> { private int index; private String filename; private long start, end; private String urlString; DownloadThread(int index, long start, long end, String url) { this.urlString = url; this.index = index; this.start = start; this.end = end; if (path.equals("")) { this.filename = prefix + "-temp-" + index; } else { this.filename = path + "/" + prefix + "-temp-" + index; } } @Override public DownloadTemp call() throws Exception { URL url = new URL(urlString); HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection(); httpURLConnection.setRequestMethod("GET"); httpURLConnection.setRequestProperty("Range", "bytes=" + start + "-" + end); InputStream inputStream = null; OutputStream outputStream = null; try { inputStream = httpURLConnection.getInputStream(); File file = new File(filename); outputStream = new FileOutputStream(file); while (true) { byte[] bytes = new byte[10240]; int length = inputStream.read(bytes); if (length <= 0) { break; } outputStream.write(bytes, 0, length); } outputStream.flush(); } finally { if (inputStream != null) { inputStream.close(); } if (outputStream != null) { outputStream.close(); } } DownloadTemp downloadTemp = new DownloadTemp(); downloadTemp.index = index; downloadTemp.filename = filename; System.out.println("thread\t" + index + "\tcompleted."); return downloadTemp; } } private static class DownloadTemp { private int index; private String filename; } }
3.使用Jar包
下载工具 download-1.0.jar下载下来后,改名为
download-1.0.jar,执行:
java -jar download-1.0.jar https://blog.dubby.cn/upload/2018-01-13/68b780a2-1a6c-49dc-914e-0469cb969471.zip /Users/test/Desktop/download 15
其中有三个参数:
下载的URL,必填
下载到目标目录,选填,如果不指定,下载到当前目前下
开启的线程数,选填,默认是10个线程
测试结果:
➜ target java -jar download-1.0.jar https://blog.dubby.cn/upload/2018-01-13/68b780a2-1a6c-49dc-914e-0469cb969471.zip /Users/test/Desktop/download 15 Download started, url is "https://blog.dubby.cn/upload/2018-01-13/68b780a2-1a6c-49dc-914e-0469cb969471.zip" Content-Length 1MB start: 0 end: 83780 start: 83781 end: 167561 start: 167562 end: 251342 start: 251343 end: 335123 start: 335124 end: 418904 start: 418905 end: 502685 start: 502686 end: 586466 start: 586467 end: 670247 start: 670248 end: 754028 start: 754029 end: 837809 start: 837810 end: 921590 start: 921591 end: 1005371 start: 1005372 end: 1089152 start: 1089153 end: 1172933 start: 1172934 end: 1256726 thread 0 completed. thread 10 completed. thread 1 completed. thread 9 completed. thread 14 completed. thread 11 completed. thread 7 completed. thread 6 completed. thread 2 completed. thread 4 completed. thread 3 completed. thread 8 completed. thread 12 completed. thread 13 completed. thread 5 completed. cost 9s
相关文章推荐
- 1 多线程下载一个文件(普通的java工程:java实现)
- 【java编程】IO特殊类之RandomAccessFile实现多线程文件下载
- Java中使用多线程实现文件上传和下载
- java多线程实现文件下载功能
- java实现多线程下载网络文件
- Java 实现多线程文件下载(HTTP)
- 使用java实现http多线程断点下载文件(一)
- OSS实现多文件多线程的断点下载(java)
- 28.java多线程实现文件的下载
- Java实现多线程文件下载的代码示例
- 运用java.net.HttpURLConnection实现java多线程下载文件
- 使用java实现http多线程断点下载文件(二)
- Java实现文件下载功能
- java实现pdf文件下载
- 用JAVA实现ORACLE数据库的文件上传、下载
- 如何实现java文件队列下载
- 用Java实现HTTP文件队列下载
- Java实现文件下载功能
- jsp里使用java excel api实现文件下载
- Java实现HTTP文件下载