多线程下载文件

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

涉及的知识及问题

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

一.请求的数据怎么拆分

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

二.拆分完成后怎么下载

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

三.如何计算实时下载量

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

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

下面贴上全部的代码

  1. public class DownLoadUtile {
  2. public static String filePath="C:\\Users\\Administrator\\Desktop\\下载\\ deme.exe"; //文件保存地址
  3. 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";//文件地址
  4. public static int threadCount=5; //线程数量
  5. public static int fileLength=0; //文件大小
  6. public static Thread [] threadList=new Thread[threadCount];
  7.  
  8. public DownLoadUtile() {
  9.  
  10. }
  11. public DownLoadUtile(int threadCount) {//有参构造
  12. this.threadCount=threadCount;
  13. }
  14.  
  15. public static void main(String[] args) throws Exception {
  16. URL url=new URL(fileUrl);
  17. HttpURLConnection conn = (HttpURLConnection) url.openConnection(); //创建连接对象
  18. conn.setConnectTimeout(5000);//请求超时时间
  19.  
  20. int code = conn.getResponseCode();
  21. System.out.println("服务器响应码"+code);
  22. if(code==200) {//响应正常
  23. fileLength=conn.getContentLength(); //获取文件大小
  24. File file = new File(filePath);
  25. if(!file.exists()) {
  26. file.createNewFile();
  27. }
  28. RandomAccessFile raf = new RandomAccessFile(filePath, "rwd"); //断点续传的关键
  29. raf.setLength(fileLength);
  30.  
  31. int blockSize =fileLength/threadCount; //计算每个线程需要下的长度
  32. for(int i=0;i<threadCount;i++) {
  33. int startSize=i*blockSize; //当前线程需要下载的开始位置
  34. int endSize=(i+1)*blockSize-1;//当前线程需要下载的结束位置
  35. if(1+i==threadCount) { //最后一个线程的结尾赋值文件大小
  36. endSize=fileLength;
  37. }
  38. threadList[i]= new DownThread_1(filePath, fileUrl, "线程"+i, startSize, endSize);
  39. threadList[i].start();
  40. }
  41.  
  42. while(DownUtile.downOver) {
  43. Thread.sleep(500); //间隔0.5秒计算一下
  44. if(DownUtile.downLength==fileLength) {
  45. DownUtile.downOver=false;
  46. System.out.println("下载完成:100%");
  47. }else {
  48. System.out.println("已经下载了:"+((int) (float)DownUtile.downLength / (float) fileLength * 100)+"%");
  49. }
  50. }
  51.  
  52. }else {
  53. System.out.println("服务器响应失败"+code);
  54. }
  55.  
  56. }

下载类

  1. public class DownThread_1 extends Thread{
  2.  
  3. private String filePath;
  4. private String urlPath;
  5. private String threadName;
  6. private int startSize;
  7. private int endSize;
  8.  
  9. public DownThread_1(String filePath,String urlPath,String threadName,int startSize,int endSize) {
  10. this.endSize=endSize;
  11. this.startSize=startSize;
  12. this.filePath=filePath;
  13. this.urlPath=urlPath;
  14. this.threadName=threadName;
  15. }
  16. @Override
  17. public void run() {
  18. try {
  19. URL url = new URL(urlPath);
  20. HttpURLConnection coon = (HttpURLConnection) url.openConnection();
  21. coon.setRequestProperty("range","bytes="+startSize+"-"+endSize); //设置获取下载资源的开始位置和结束位置
  22. coon.setConnectTimeout(5000);
  23. if(coon.getResponseCode()==206) {//响应码 因为上面设置了range 所有响应码是206不再是200
  24. BufferedInputStream bi=new BufferedInputStream(coon.getInputStream());
  25. RandomAccessFile raf=new RandomAccessFile(filePath, "rwd"); //断点续传的关键
  26. raf.seek(startSize); //将写入点移动到当前线程写入开始位置
  27. byte b[]=new byte[1024];
  28. int len=0;
  29. while ((len=bi.read(b))>-1) { //循环写入
  30. raf.write(b, 0, len);
  31. synchronized (DownUtile.class) {//此处涉及到变量同步
  32. DownUtile.downLength=DownUtile.downLength+len; //计算当前下载了多少
  33. }
  34. }
  35. raf.close();
  36. bi.close();
  37. System.out.println("thread"+threadName+"下载完成,开始位置"+startSize+",结束位置"+endSize);
  38. }
  39. } catch (MalformedURLException e) {
  40. e.printStackTrace();
  41. } catch (IOException e) {
  42. e.printStackTrace();
  43. }
  44. }
  45.  
  46. }

参数类

  1. public class DownUtile {
  2.  
  3. public static int downLength=0;//已经下载了多少
  4.  
  5. public static boolean downOver=true; //下载是否完成
  6.  
  7. }

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. mvc Bundling 学习记录(一)

    参考博客:http://www.cnblogs.com/xwgli/p/3296809.html 这里要详细记录的是对于现有MVC项目进行Bundling功能 1  如果没有System.Web.Op ...

  2. Android4.4 GPS框架分析【转】

    本文转载自:http://blog.csdn.net/junzhang1122/article/details/46674569 GPS HAL层代码在目录trunk/Android/hardware ...

  3. c# XML-Object对象 序列化-反序列化

    using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Tex ...

  4. matlab高亮显示选中的变量

    第一步:点preference. 第二步:

  5. nodejs socket.io初探

    1.安装socket.io npm install socket.io 2.创建服务端代码server.js var app = require('http').createServer(handle ...

  6. linux命令学习笔记(47):iostat命令

    Linux系统中的 iostat是I/O statistics(输入/输出统计)的缩写,iostat工具将对系统的磁盘操作活动进行监视. 它的特点是汇报磁盘活动统计情况,同时也会汇报出CPU使用情况. ...

  7. codewar代码练习1——8级晋升7级

    最近发现一个不错的代码练习网站codewar(http://www.codewars.com).注册了一个账号,花了几天的茶余饭后时间做题,把等级从8级升到了7级.本文的目的主要介绍使用感受及相应题目 ...

  8. 查询oracle 数据库 SQL语句执行情况

    1.查看总消耗时间最多的前10条SQL语句 select *  from (select v.sql_id,  v.child_number,  v.sql_text,  v.elapsed_time ...

  9. terminate called after throwing an instance of 'std::out_of_range' what(): basic_string::substr

    运行时报错: terminate called after throwing an instance of 'std::out_of_range'what():  basic_string::subs ...

  10. navicat 关于orcale新建表空间,用户和权限分配

    图文教程,直观, 上面连接数据库 下面创建表空间 建表空间的设置 表空间名的设置 新建用户 填写用户名,选择默认表空间 成员属性德设置,这里因为是自己用,所以选择最大权限,其他的权限这是需要专业的了 ...