多线程下载
2016-05-13 22:33
190 查看
原理
在本地创建一个大小跟服务器文件相同大小的临时文件。计算分配几个线程去下载服务器上的资源,知道每个线程下载文件的位置。
步骤二的具体方法和操作:
文件的长度/3(线程的个数)=每个线程下载文件的大小
假设文件长度为10,则
线程1:0-2
线程2:3-5
线程3:6-文件末尾
每个线程下载的位置的计算方式:
开始位置:
(线程id - 1)* 每一块的大小
结束位置:
(线程id * 每一块大小)-1
开启多(3)个线程,每一个线程下载对应位置的文件
如果所有的线程都把自己的数据下载完毕了,服务器上的资源就被下载到本地了。
在这里在介绍一个有关多线程下载的java中的相关类RandomAccessFile
RandomAccessFile 随机文件访问类
只有RandomAccessFile才有seek搜寻方法,而这个方法也只适用于文件。通过seek()方法指定位置,定位文件,即可以指定随机写文件的时候从哪个位置开始写。利用这个类才能实现文件的多线程下载。
基本原理和相关介绍如上,就这些,现在我们看看代码:
public class MutilDownloader { // 开启的线程的个数 public static final int THREAD_COUNT = 3; public static void main(String[] args) throws Exception { String path = "http://down.360safe.com/yunpan/360wangpan_setup.exe"; // 连接服务器,获取一个文件,获取文件的长度,在本地创建一个大小跟服务器文件大小一样的临时文件 URL url = new URL(path); //打开链接 HttpURLConnection conn = (HttpURLConnection) url.openConnection(); // 设置网络请求超时时间 conn.setConnectTimeout(5000); // 设置请求方式 conn.setRequestMethod("GET"); //获取响应码 int code = conn.getResponseCode(); if (code == 200) { // 服务器返回的数据的长度,实际就是文件的长度 int length = conn.getContentLength(); System.out.println("----文件总长度----" + length); // 在客户端本地创建出来一个大小跟服务器端文件一样大小的临时文件 RandomAccessFile raf = new RandomAccessFile("yunpan.exe", "rwd"); // 指定创建的这个文件的长度 raf.setLength(length); // 关闭raf raf.close(); // 假设是3个线程去下载资源 // 平均每一个线程下载的文件的大小 int blockSize = length / THREAD_COUNT; for (int threadId = 1; threadId <= THREAD_COUNT; threadId++) { // 计算每个线程下载的开始位置和结束位置 int startIndex = (threadId - 1) * blockSize; int endIndex = threadId * blockSize - 1; if (threadId == THREAD_COUNT) { endIndex = length; } System.out.println("----threadId---" + threadId + "--startIndex--" + startIndex + "--endIndex--" + endIndex); // 开启每一个线程 new DownloadThread(path, threadId, startIndex, endIndex) .start(); } } } /** * 下载文件的子线程,每一个线程下载对应位置的文件 * * @author loonggg * */ public static class DownloadThread extends Thread { private int threadId; private int startIndex; private int endIndex; private String path; /** * @param path * 下载文件在服务器上的路径 * @param threadId * 线程id * @param startIndex * 线程下载的开始位置 * @param endIndex * 线程下载的结束位置 */ public DownloadThread(String path, int threadId, int startIndex, int endIndex) { this.path = path; this.threadId = threadId; this.startIndex = startIndex; this.endIndex = endIndex; } @Override public void run() { try { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url .openConnection(); conn.setRequestMethod("GET"); // 重要:请求服务器下载部分的文件 指定文件的位置 conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex); conn.setConnectTimeout(5000); // 从服务器请求全部资源的状态码200 ok 如果从服务器请求部分资源的状态码206 ok int code = conn.getResponseCode(); System.out.println("---code---" + code); InputStream is = conn.getInputStream();// 已经设置了请求的位置,返回的是当前位置对应的文件的输入流 RandomAccessFile raf = new RandomAccessFile("yunpan.exe", "rwd"); // 随机写文件的时候从哪个位置开始写 raf.seek(startIndex);// 定位文件 int len = 0; byte[] buffer = new byte[1024]; while ((len = is.read(buffer)) != -1) { raf.write(buffer, 0, len); } is.close(); raf.close(); System.out.println("线程" + threadId + ":下载完毕了!"); } catch (Exception e) { e.printStackTrace(); } } } }
相关文章推荐
- 第二节windows系统下Xshell 5软件远程访问虚拟机 Linux系统
- POJ——4565So Easy!(矩阵快速幂)
- 练习: C#---函数(篮球弹起高度、等腰三角形)
- SM2算法第七篇:Windows下Openssl安装与配置
- 安装saltstack遇到缺包问题!自己遇到的错!若有雷同请海涵
- marquee 笔记
- Python 分解带括号的字符串
- win10 Mysql server 安装
- MySQL 添加列+修改列+删除列
- 解决ssh免密码登录仍然提示输入密码问题
- Idea的插件
- 移动APP项目优化
- Codeforces Round #136 (Div. 2)D(codeforces221d) 暴力!!!!
- 使用VS2010自定义C++模板
- ViewConfiguration.getScaledTouchSlop () 用法
- 使用并查集判断无向图是否连通
- Error:Flash Download Failed-"Cortex-M3"
- Error:Flash Download Failed-"Cortex-M3"
- 谈情--读《白马啸西风》有感
- HTTP协议规范RFC文档的几个版本更新