基于HTTP的多线程文件下载功能实现
2016-12-08 19:33
633 查看
思想
文件信息获取的获取方式与单线程的方式一样与单线程相比不同的是将远程文件分块并发获取,然后再并发写入到本地暂存文件中
远程文件分块的实现依据是:connection.setRequestProperty(“Range”,”bytes=”+start+”-“+end)
本地将文件写入指定位置的实现依据是:RandomAccessFile
代码实现
package org.hanmeis; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicLong; import java.util.logging.Logger; /** * Created by zhao.wu on 2016/12/7. * 多线程下载器 * 1. 使用{@see RandomAccessFile}在文件任意位置写入内容 * 2. 使用 {@code connection.setRequestProperty("Range","bytes="+start+"-"+end);}设置从服务器上读取的文件块。 */ public class MuiltDownloader { private static Log d9ad ger logger = Logger.getLogger("MuiltDownloader"); public static void main(String[] args) throws IOException, InterruptedException, ExecutionException { String url = "http://dlsw.baidu.com/sw-search-sp/soft/e7/40642/Git-2.7.2-64-bit_setup.1457942968.exe"; MuiltDownloader muiltDownloader = new MuiltDownloader(url, 10); muiltDownloader.connectServer(); muiltDownloader.startDownload(); } private AtomicLong currentSize = new AtomicLong(0l); private long preSize; private long fileSize; private String realFileName; private String tempFileName; private String urlStr; private int taskNum; private Timer timer = new Timer(); private MuiltDownloader(String urlStr, int taskNum) { logger.info("新任务加入下载队列......"); this.urlStr = urlStr; this.taskNum = taskNum; this.tempFileName = UUID.randomUUID().toString().replace("-", ""); } private void connectServer() throws IOException { URL url = new URL(urlStr); logger.info(String.format("连接服务器:%s://%s",url.getProtocol(),url.getHost())); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setConnectTimeout(10 * 1000); this.fileSize = Long.parseLong(connection.getHeaderField("Content-Length")); String[] temp = url.getFile().split("/"); if (temp.length != 0) { this.realFileName = temp[temp.length - 1]; } logger.info(String.format("文件名:%s 大小:%.2fM", this.realFileName, this.fileSize*1.0/1024/1024)); RandomAccessFile randomAccessFile = new RandomAccessFile(tempFileName,"rw"); randomAccessFile.setLength(fileSize); randomAccessFile.close(); } private void startDownload() throws InterruptedException, ExecutionException { long foot = fileSize / taskNum; long rest = fileSize % taskNum; List<BlockDownLoadTask> tasks = new ArrayList<>(); for (int i = 0; i < taskNum; i++) { logger.info(String.format("初始化第%d个下载线程", i+1)); BlockDownLoadTask task; if (i < taskNum - 1) { task = new BlockDownLoadTask(tempFileName, urlStr, i * foot, (i + 1) * foot - 1, currentSize); } else { task = new BlockDownLoadTask(tempFileName, urlStr, i * foot, fileSize, currentSize); } tasks.add(task); } logger.info(String.format("开始下载:%s",realFileName)); info(); ExecutorService service = Executors.newFixedThreadPool(taskNum); service.invokeAll(tasks); service.shutdownNow(); timer.cancel(); File file = new File(tempFileName); file.renameTo(new File(realFileName)); logger.info(String.format("完成下载:%s",realFileName)); } /** * 定时计算下载状态 */ private void info(){ timer.schedule(new TimerTask() { @Override public void run() { long tempC = currentSize.get(); long tempSize = tempC-preSize; preSize = tempC; double percent = (tempC*100.0)/fileSize; double speed = (tempSize*1.0)/1024/3; logger.info(String.format("文件:%s 已完成:%.2f%% 速率:%.2fkb/s",realFileName, percent, speed)); } },0, 3000); } } class BlockDownLoadTask implements Callable<String> { private String tempFileName; private String urlStr; private long startPosition; private long endPosition; private AtomicLong currentSize; BlockDownLoadTask(String tempFileName, String urlStr, long startPosition, long endPosition, AtomicLong currentSize) { this.tempFileName = tempFileName; this.urlStr = urlStr; this.startPosition = startPosition; this.endPosition = endPosition; this.currentSize = currentSize; } @Override public String call() throws Exception { URL url = new URL(urlStr); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestProperty("Range", "bytes=" + startPosition + "-" + endPosition); InputStream is = connection.getInputStream(); RandomAccessFile randomAccessFile = new RandomAccessFile(tempFileName, "rwd"); randomAccessFile.seek(startPosition); byte[] bs = new byte[1024]; int len; while ((len = is.read(bs)) > 0) { randomAccessFile.write(bs); currentSize.addAndGet(len); } randomAccessFile.close(); is.close(); return Thread.currentThread().getName(); } }
相关文章推荐
- 基于HTTP的单线程文件下载功能实现
- Java 实现多线程文件下载(HTTP)
- ios开发视频播放后台下载功能实现 :1,ios播放视频 ,包含基于AVPlayer播放器,2,实现下载,iOS后台下载(多任务同时下载,单任务下载,下载进度,下载百分比,文件大小,下载状态)(真机调试功能正常)
- 发一个多线程通过 HTTP 下载文件的类(Linux下的实现)
- 用 C# 实现 HTTP 协议多线程下载文件
- java resteasy restful webservice教程(六):实现文件下载功能实例文章来源:爱上123 原文地址:http://www.ishang123.com/jishubowen/
- Java servlet 简单实现http文件下载断点续传功能
- java多线程实现文件下载功能
- windows基于阿帕奇服务器,实现vc++文件下载功能
- 基于struts 的实现文件的下载和删除功能
- Golang+Android基于HttpURLConnection实现的文件上传功能示例
- 基于RandomAccessFile实现断点文件下载功能
- 基于Java文件输入输出流实现文件上传下载功能
- 使用java实现http多线程断点下载文件(二)
- AngularJS基于http请求实现下载php生成的excel文件功能示例
- C#实现http多线程下载文件
- 基于NoHttp+RxBus+MVP实现网络文件下载(带进度条)
- 使用java实现http多线程断点下载文件(一)
- 基于NoHttp+RxBus实现文件下载(带下载进度)
- 优雅设计封装基于Okhttp3的网络框架(三):多线程下载功能核心实现 及 线程池、队列机制、终止线程解析