多线程下载文件

多线程同时下载文件即:在同一时间内通过多个线程对同一个请求地址发起多个请求,将需要下载的数据分割成多个部分,同时下载,每个线程只负责下载其中的一部分,最后将每一个线程下载的部分组装起来即可。

涉及的知识及问题

  • 请求的数据怎么拆分
  • 拆分完成后怎么下载
  • 如何计算实时下载量

一.请求的数据怎么拆分

 int blockSize =fileLength/threadCount; //计算每个线程需要下的长度
for(int i=0;i<threadCount;i++) {
int startSize=i*blockSize; //当前线程需要下载的开始位置
int endSize=(i+1)*blockSize-1;//当前线程需要下载的结束位置
if(1+i==threadCount) { //最后一个线程的结尾赋值文件大小
endSize=fileLength;
}
threadList[i]= new DownThread_1(filePath, fileUrl, "线程"+i, startSize, endSize);
threadList[i].start();
}

二.拆分完成后怎么下载

try {
URL url = new URL(urlPath);
HttpURLConnection coon = (HttpURLConnection) url.openConnection();
coon.setRequestProperty("range","bytes="+startSize+"-"+endSize); //设置获取下载资源的开始位置和结束位置
coon.setConnectTimeout(5000);
if(coon.getResponseCode()==206) {//响应码 因为上面设置了range 所有响应码是206不再是200
BufferedInputStream bi=new BufferedInputStream(coon.getInputStream());
RandomAccessFile raf=new RandomAccessFile(filePath, "rwd"); //断点续传的关键
raf.seek(startSize); //将写入点移动到当前线程写入开始位置
byte b[]=new byte[1024];
int len=0;
while ((len=bi.read(b))>-1) { //循环写入
raf.write(b, 0, len);
synchronized (DownUtile.class) {//此处涉及到变量同步
DownUtile.downLength=DownUtile.downLength+len; //计算当前下载了多少
}
}
raf.close();
bi.close();
System.out.println("thread"+threadName+"下载完成,开始位置"+startSize+",结束位置"+endSize);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

三.如何计算实时下载量

    while ((len=bi.read(b))>-1) { //循环写入
raf.write(b, 0, len);
synchronized (DownUtile.class) {//此处涉及到变量同步
DownUtile.downLength=DownUtile.downLength+len; //计算当前下载了多少
}
} while(DownUtile.downOver) {
Thread.sleep(500); //间隔0.5秒计算一下
if(DownUtile.downLength==fileLength) {
DownUtile.downOver=false;
System.out.println("下载完成:100%");
}else {
System.out.println("已经下载了:"+((int) (float)DownUtile.downLength / (float) fileLength * 100)+"%");
}
}

上述方法中  用到了synchronized(类锁),为什么用到类锁,因为计算下载的参数在DownUtile类中,为了保证这个参数在多线程中同步,需保证在执行累加操作时线程安全。

下面贴上全部的代码

 public class DownLoadUtile {
public static String filePath="C:\\Users\\Administrator\\Desktop\\下载\\ deme.exe"; //文件保存地址
public static String fileUrl="http://123.6.39.120/dlied1.qq.com/lol/dltools/LOL_V4.1.2.3-V4.1.2.4_PATCH_0_tgod_signed.exe?mkey=5cfc8d87dddd9a57&f=5844&cip=221.221.188.162&proto=http";//文件地址
public static int threadCount=5; //线程数量
public static int fileLength=0; //文件大小
public static Thread [] threadList=new Thread[threadCount]; public DownLoadUtile() { }
public DownLoadUtile(int threadCount) {//有参构造
this.threadCount=threadCount;
} public static void main(String[] args) throws Exception {
URL url=new URL(fileUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection(); //创建连接对象
conn.setConnectTimeout(5000);//请求超时时间 int code = conn.getResponseCode();
System.out.println("服务器响应码"+code);
if(code==200) {//响应正常
fileLength=conn.getContentLength(); //获取文件大小
File file = new File(filePath);
if(!file.exists()) {
file.createNewFile();
}
RandomAccessFile raf = new RandomAccessFile(filePath, "rwd"); //断点续传的关键
raf.setLength(fileLength); int blockSize =fileLength/threadCount; //计算每个线程需要下的长度
for(int i=0;i<threadCount;i++) {
int startSize=i*blockSize; //当前线程需要下载的开始位置
int endSize=(i+1)*blockSize-1;//当前线程需要下载的结束位置
if(1+i==threadCount) { //最后一个线程的结尾赋值文件大小
endSize=fileLength;
}
threadList[i]= new DownThread_1(filePath, fileUrl, "线程"+i, startSize, endSize);
threadList[i].start();
} while(DownUtile.downOver) {
Thread.sleep(500); //间隔0.5秒计算一下
if(DownUtile.downLength==fileLength) {
DownUtile.downOver=false;
System.out.println("下载完成:100%");
}else {
System.out.println("已经下载了:"+((int) (float)DownUtile.downLength / (float) fileLength * 100)+"%");
}
} }else {
System.out.println("服务器响应失败"+code);
} }

下载类

 public class DownThread_1 extends Thread{

     private String filePath;
private String urlPath;
private String threadName;
private int startSize;
private int endSize; public DownThread_1(String filePath,String urlPath,String threadName,int startSize,int endSize) {
this.endSize=endSize;
this.startSize=startSize;
this.filePath=filePath;
this.urlPath=urlPath;
this.threadName=threadName;
}
@Override
public void run() {
try {
URL url = new URL(urlPath);
HttpURLConnection coon = (HttpURLConnection) url.openConnection();
coon.setRequestProperty("range","bytes="+startSize+"-"+endSize); //设置获取下载资源的开始位置和结束位置
coon.setConnectTimeout(5000);
if(coon.getResponseCode()==206) {//响应码 因为上面设置了range 所有响应码是206不再是200
BufferedInputStream bi=new BufferedInputStream(coon.getInputStream());
RandomAccessFile raf=new RandomAccessFile(filePath, "rwd"); //断点续传的关键
raf.seek(startSize); //将写入点移动到当前线程写入开始位置
byte b[]=new byte[1024];
int len=0;
while ((len=bi.read(b))>-1) { //循环写入
raf.write(b, 0, len);
synchronized (DownUtile.class) {//此处涉及到变量同步
DownUtile.downLength=DownUtile.downLength+len; //计算当前下载了多少
}
}
raf.close();
bi.close();
System.out.println("thread"+threadName+"下载完成,开始位置"+startSize+",结束位置"+endSize);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} }

参数类

 public class DownUtile {

     public static  int downLength=0;//已经下载了多少

     public static boolean downOver=true; //下载是否完成

 }

java 多线程下载文件并实时计算下载百分比(断点续传)的更多相关文章

  1. [Swift通天遁地]四、网络和线程-(8)下载图片并实时显示下载进度

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...

  2. JAVA多线程读写文件范例

    在写之前先声明,本文是基于之前在博客园网站上检索到的一份JAVA多线程读写文件的示例,我在写自己的程序时是在那位作者写的基础上做了改良,但已不记得原文的地址.如果有知情者,烦请帖出地址,我在此文上加入 ...

  3. 09_多线程下载_获取文件长度&计算下载范围

    package com.itheima.multiThreadDownload; //import java.net.MalformedURLException; import java.io.Ran ...

  4. Java实现FTP文件上传与下载

    实现FTP文件上传与下载可以通过以下两种种方式实现(不知道还有没有其他方式),分别为:1.通过JDK自带的API实现:2.通过Apache提供的API是实现. 第一种方式 package com.cl ...

  5. Java实现对文件的上传下载操作

    通过servlet,实现对文件的上传功能 1.首先创建一个上传UploadHandleServlet ,代码如下: package me.gacl.web.controller; import jav ...

  6. 【Java】JavaWeb文件上传和下载

    文件上传和下载在web应用中非常普遍,要在jsp环境中实现文件上传功能是非常容易的,因为网上有许多用java开发的文件上传组件,本文以commons-fileupload组件为例,为jsp应用添加文件 ...

  7. java实现大文件上传和下载

    [文件上传和下载]是很多系统必备功能, 比如PM\OA\ERP等:系统中常见的开发模式有B/S和C/S,而前者主要是通过浏览器来访问web服务器,一般采用七层协议中的[应用层http]进行数据传输,后 ...

  8. Java 实现ftp 文件上传、下载和删除

    本文利用apache ftp工具实现文件的上传下载和删除.具体如下: 1.下载相应的jar包 commons-net-1.4.1.jar 2.实现代码如下: public class FtpUtils ...

  9. Java中的文件上传和下载

    文件上传原理: 早期的文件上传机制: 在TCP/IP中.最早出现的文件上传机制是FTP.他是将文件由客户端发送到服务器的标准机制. jsp中的文件上传机制: 在jsp编程中不能使用FTP的方法来上传文 ...

随机推荐

  1. com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '88888888' for key 'PRIMARY'

    严重: Servlet.service() for servlet jsp threw exceptioncom.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityC ...

  2. B. Drazil and His Happy Friends

    这是 Codeforces Round #292 (Div. 2)的一道题,原题在这里,题意就是: 小明有n个男同学(编号为 0 ~ n-1)和m个女同学 (编号为 0 ~ m-1),小明要安排男女之 ...

  3. mini2440 u-boot下设置tftp

    在烧写好u-boot后,重新启动mini2440,一直按空格键进入u-boot界面: U-Boot 月 - ::) modified by tekkamanninja (tekkamanninja@. ...

  4. js_调试_01_14 个你可能不知道的 JavaScript 调试技巧

    更快更高效地调试你的 JavaScript 了解你的工具在完成任务时有很重要的意义. 尽管 JavaScript 是出了名的难以调试,但是如果你掌握了一些小技巧,错误和 bug 解决起来就会快多了. ...

  5. poj 2689Prime Distance(区间素数)埃氏筛法

    这道题的L和R都很大,所以如果直接开一个1~R的数组明显会超时.但是R-L并不大,所以我们考虑把这个区间(L--R)移动到(1--(R-L+1))这个区间再开数组(就是把每个数减L再加1).接下来先用 ...

  6. ACM学习历程—ZOJ3471 Most Powerful(dp && 状态压缩 && 记忆化搜索 && 位运算)

    Description Recently, researchers on Mars have discovered N powerful atoms. All of them are differen ...

  7. WPF TreeView 后台C#选中指定的Item, 需要遍历

               private TreeViewItem FindTreeViewItem(ItemsControl container, object item)         {      ...

  8. PHP生成唯一的订单号

    记:之前面试的时候被面试官问过简历项目中的订单号我是什么规则生成的,我牛逼吹过头了,乱说了一通,靠!今天在公司的项目中订单号生成,好奇,看了下,就是网上的这种而已. * * uniqid - 官方是这 ...

  9. ubuntu下caffe配置

    http://blog.csdn.net/yhaolpz/article/details/71375762

  10. linux下的函数dirname()和basename()使用

    总览 #include <libgen.h> char *dirname(char *path); char *basename(char *path); 说明 函数以 '/' 为分隔符 ...