多线程下载文件的过程是:

(1)首先获得下载文件的长度,然后设置本地文件的长度。

HttpURLConnection.getContentLength();//获取下载文件的长度

RandomAccessFile file = new RandomAccessFile("QQSetup.exe","rwd");

file.setLength(filesize);//设置本地文件的长度

(2)根据文件长度和线程数计算每条线程下载的数据长度和下载位置。

如:文件的长度为6M,线程数为3,那么,每条线程下载的数据长度为2M,每条线程开始下载的位置如下图所示。

例如10M大小,使用3个线程来下载,

线程下载的数据长度   (10%3 == 0 ? 10/3:10/3+1) ,第1,2个线程下载长度是4M,第三个线程下载长度为2M

下载开始位置:线程id*每条线程下载的数据长度 = ?

下载结束位置:(线程id+1)*每条线程下载的数据长度-1=?

(3)使用Http的Range头字段指定每条线程从文件的什么位置开始下载,下载到什么位置为止,

如:指定从文件的2M位置开始下载,下载到位置(4M-1byte)为止

代码如下:HttpURLConnection.setRequestProperty("Range", "bytes=2097152-4194303");

(4)保存文件,使用RandomAccessFile类指定每条线程从本地文件的什么位置开始写入数据。

RandomAccessFile threadfile = new RandomAccessFile("QQWubiSetup.exe ","rwd");

threadfile.seek(2097152);//从文件的什么位置开始写入数据

/** *多线程下载,UI更新类  *@author young * */
public class MultiThreadDownload extends Thread{  private static final String TAG = "MultiThreadDownload";  /**每一个线程需要下载的大小 */  private int blockSize;  /*** 线程数量<br> 默认为5个线程下载*/  private int threadNum = 5;  /*** 文件大小 */  private int fileSize;  /** * 已经下载多少 */  private int downloadSize;  /**文件的url,线程编号,文件名称*/  private String UrlStr,ThreadNo,fileName;  /***保存的路径*/  private String savePath;  /**下载的百分比*/  private int downloadPercent = 0;  /**下载的 平均速度*/  private int downloadSpeed = 0;  /**下载用的时间*/  private int usedTime = 0;  /**当前时间*/  private long curTime;  /**是否已经下载完成*/  private boolean completed = false;  private Handler handler ;  /** * 下载的构造函数   * @param url  请求下载的URL * @param handler   UI更新使用 * @param savePath  保存文件的路径 */  public MultiThreadDownload(Handler handler,String url,String savePath)  {  this.handler = handler;  this.UrlStr = url;  this.savePath = savePath;  Log.e(TAG, toString());  }  @Override  public void run() {  FileDownloadThread[] fds = new FileDownloadThread[threadNum];//设置线程数量  try {  URL url = new URL(UrlStr);  URLConnection conn = url.openConnection();  fileSize = conn.getContentLength();  this.fileName = FileUtil.getFileName(UrlStr);  //只创建一个文件,saveFile下载内容  File saveFile = new File(savePath+"/"+fileName);  Log.e(TAG, "文件一共:"+fileSize+" savePath "+savePath+"  fileName  "+fileName);  RandomAccessFile accessFile = new RandomAccessFile(saveFile,"rwd");  //设置本地文件的长度和下载文件相同     accessFile.setLength(fileSize);    accessFile.close();  //Handler更新UI,发送消息  sendMsg(FileUtil.startDownloadMeg);  //每块线程下载数据  blockSize = ((fileSize%threadNum)==0)?(fileSize/threadNum):(fileSize/threadNum+1);  Log.e(TAG, "每个线程分别下载 :"+blockSize);  for (int i = 0; i < threadNum; i++) {  int curThreadEndPosition = (i+1)!=threadNum ? ((i+1)*blockSize-1) : fileSize;  FileDownloadThread fdt = new FileDownloadThread(url, saveFile, i*blockSize, curThreadEndPosition);  fdt.setName("thread"+i);  fdt.start();  fds[i]=fdt;  }  /** * 获取数据,更新UI,直到所有下载线程都下载完成。 */  boolean finished = false;  //开始时间,放在循环外,求解的usedTime就是总时间  long startTime = System.currentTimeMillis();  while(!finished)  {  downloadSize = 0;  finished = true;  for (int i = 0; i < fds.length; i++) {  downloadSize+= fds[i].getDownloadSize();  if(!fds[i].isFinished())  {  finished = false;  }  }  downloadPercent = (downloadSize*100)/fileSize;  curTime = System.currentTimeMillis();  System.out.println("curTime = "+curTime+" downloadSize = "+downloadSize+" usedTime "+(int) ((curTime-startTime)/1000));  usedTime = (int) ((curTime-startTime)/1000);  if(usedTime==0)usedTime = 1;    downloadSpeed = (downloadSize/usedTime)/1024;  sleep(1000);/*1秒钟刷新一次界面*/  sendMsg(FileUtil.updateDownloadMeg);  }  Log.e(TAG, "下载完成");  completed = true;  sendMsg(FileUtil.endDownloadMeg);  } catch (Exception e) {  Log.e(TAG, "multi file error  Exception  "+e.getMessage());  e.printStackTrace();  }  super.run();  }  /** * 得到文件的大小 * @return */  public int getFileSize()  {  return this.fileSize;  }  /** * 得到已经下载的数量 * @return */  public int getDownloadSize()  {  return this.downloadSize;  }  /** * 获取下载百分比 * @return */  public int getDownloadPercent(){  return this.downloadPercent;  }  /** * 获取下载速度 * @return */  public int getDownloadSpeed(){  return this.downloadSpeed;  }  /** * 修改默认线程数 * @param threadNum */  public void setThreadNum(int threadNum){  this.threadNum = threadNum;  }  /** * 分块下载完成的标志 * @return */  public boolean isCompleted(){  return this.completed;  }  @Override  public String toString() {  return "MultiThreadDownload [threadNum=" + threadNum + ", fileSize="  + fileSize + ", UrlStr=" + UrlStr + ", ThreadNo=" + ThreadNo  + ", savePath=" + savePath + "]";  }  /** * 发送消息,用户提示 * */  private void sendMsg(int what)  {  Message msg = new Message();  msg.what = what;  handler.sendMessage(msg);  } 
public class FileDownloadThread extends Thread{  private static final String TAG = "FileDownloadThread";  /**缓冲区 */  private static final int BUFF_SIZE = 1024;  /**需要下载的URL*/  private URL url;  /**缓存的FIle*/  private File file;  /**开始位置*/  private int startPosition;  /**结束位置*/  private int endPosition;  /**当前位置*/  private int curPosition;  /**完成*/  private boolean finished = false;  /**已经下载多少*/  private int downloadSize = 0;  /*** * 分块文件下载,可以创建多线程模式 * @param url   下载的URL * @param file  下载的文件 * @param startPosition 开始位置 * @param endPosition   结束位置 */  public FileDownloadThread(URL url, File file, int startPosition,  int endPosition) {  this.url = url;  this.file = file;  this.startPosition = startPosition;  this.curPosition = startPosition;  this.endPosition = endPosition;  Log.e(TAG, toString());  }  @Override  public void run() {  BufferedInputStream bis = null;  RandomAccessFile rAccessFile = null;  byte[] buf = new byte[BUFF_SIZE];  URLConnection conn = null;  try {  conn = url.openConnection();  conn.setConnectTimeout(10000);//设置超时  conn.setReadTimeout(10000);  conn.setAllowUserInteraction(true);  System.out.println(this.getName()+" startPosition "+startPosition+" endPosition "+endPosition);  conn.setRequestProperty("Range", "bytes="+(startPosition)+"-"+endPosition);  //取剩余未下载的  rAccessFile = new RandomAccessFile(file,"rwd");//读写  //设置从什么位置开始写入数据   rAccessFile.seek(startPosition);  bis = new BufferedInputStream(conn.getInputStream(), BUFF_SIZE);  while(curPosition<endPosition)  //当前位置小于结束位置  继续下载  {  int len = bis.read(buf,0,BUFF_SIZE);  if(len==-1)   //下载完成    {   break;  }  rAccessFile.write(buf,0,len);  curPosition = curPosition +len;  if(curPosition > endPosition)  {   //如果下载多了,则减去多余部分  System.out.println("  curPosition > endPosition  !!!!");  int extraLen = curPosition-endPosition;  downloadSize += (len-extraLen+1);  }else{  downloadSize+=len;  }  }  this.finished = true;  //当前阶段下载完成  Log.e(TAG, "当前"+this.getName()+"下载完成");  } catch (Exception e) {  Log.e(TAG, "download error Exception "+e.getMessage());  e.printStackTrace();  }finally{  //关闭流  FileUtil.closeInputStream(bis);  try {  rAccessFile.close();  } catch (IOException e) {  // TODO Auto-generated catch block  Log.e("AccessFile", "AccessFile IOException "+e.getMessage());  }  }  super.run();  }  /** * 是否完成当前段下载完成 * @return */  public boolean isFinished() {  return finished;  }  /** * 已经下载多少 * @return */  public int getDownloadSize() {  return downloadSize;  }  @Override  public String toString() {  return "FileDownloadThread [url=" + url + ", file=" + file  + ", startPosition=" + startPosition + ", endPosition="  + endPosition + ", curPosition=" + curPosition + ", finished="  + finished + ", downloadSize=" + downloadSize + "]";  }

多线程下载是分段下载,创建保存一个文件,子线程分别通过RandomAccessFile类进行写入操作。

示例源码:demo下载

转载于:https://www.cnblogs.com/chaoyu/p/6436884.html

android --多线程下载相关推荐

  1. android 多线程下载,断点续传,线程池

    android 多线程下载,断点续传,线程池 你可以在这里看到这个demo的源码: https://github.com/onlynight/MultiThreadDownloader 效果图 这张效 ...

  2. 更好的Android多线程下载框架

    /*** 作者:Pich* 原文链接:http://me.woblog.cn/* QQ群:129961195* Github:https://github.com/lifengsofts*/ 概述 为 ...

  3. Android多线程下载断点续传

    先上图看卡结果: GITHUB:Android多线程下载断点续传 下载杵这儿 如图所示点击下载就开始下载,点击停止就会停止再次点击下载就会接着下载了. 设计思路是这样的: 首先通过广播将下载信息传递给 ...

  4. Android -- 多线程下载

    因为Android应用程序是java写的,基本上很多java写的程序都可以直接照搬到Android上面,移植性非常Good.这里讲一下多线程下载,就是每个线程都下载自己的那部分,那么就需要平均分配分割 ...

  5. android多线程下载原理,安卓多线程断点续传下载功能(靠谱第三方组件,原理demo)...

    一,原生的DownloadManager 从Android 2.3(API level 9)开始,Android以Service的方式提供了全局的DownloadManager来系统级地优化处理长时间 ...

  6. *Android 多线程下载 仿下载助手(改进版)

    首先声明一点: 这里的多线程下载 并不是指的 多个线程下载一个 文件,而是 每个线程 负责一个文件.真正的多线程 希望后面能给大家带来.  -------------  欢迎 爱学习的小伙伴 加群   ...

  7. android多线程下载程序卡死,android 多线程下载与断点续传

    多线程下载: 下载速度更快,服务器对每个线程平分资源,故线程越多,得到的资源越多,下载速度越快. 断点续传: 下载中断,再次下载时从上一次下载结束的位置开始下载,防止重复下载 下载结束后 代码: pa ...

  8. android多线程下载3

    今天跟大家一起分享下android开发中比较难的一个环节,可能很多人看到这个标题就会感觉头很大,的确如果没有良好的编码能力和逻辑思维,这块是很难搞明白的,前面2次总结中已经为大家分享过有关技术的一些基 ...

  9. Android 多线程下载文件原理霸气解析介绍 -----文件的下载(3)

    1.首先我们先创建好下载的位置–根据url创建文件. /*** <p>Title: FlieStorageManager</p >* <p>Description: ...

  10. Android 多线程下载以及断点续传

    多线程下载 在日常开发中,我们不可避免的会接到类似这样的需求,下载一个比较大的素材文件或者安装包文件,以此实现APP的自动更新,APP内的素材替换等.由于一般此类文件都比较大,一般会在50M以上,如果 ...

最新文章

  1. git常用命令(二)
  2. Visual Studio 2013开发 mini-filter driver step by step (3) - 查看运行结果
  3. c# treeView 取消选择事件
  4. java例程练习(布局管理器[FlowLayout])
  5. Spring MVC原理学习之how is return type handled
  6. 为什么用java开发app_安卓开发为什么选择用Java语言
  7. too many connections的一个实践
  8. texshop 使用技巧
  9. 小程序入门学习04--数据绑定、条件渲染、列表渲染
  10. 启动失败_启动失败了?
  11. Qt Creator 自动补齐变慢的解决
  12. 工具使用-----Jmeter-脚本的录制
  13. 主键和外键举例_mysql 基础篇之主键和外键
  14. 单片机喇叭如何响出报警声音 C语言程序,单片机报警器声音产生的方法(报警声音)...
  15. 穿孔发光字/外露发光字制作流程步骤
  16. 差分信号,差分对和耦合(一)——基本概念介绍
  17. [网络安全自学篇] 八十二.WHUCTF之隐写和逆向类解题思路WP(文字解密、图片解密、佛语解码、冰蝎流量分析、逆向分析)
  18. 普陀寺里的穿白T恤的奥特曼 2012年9月8日
  19. python3 教程 下载图片资源
  20. H5组件Canvas画电子印章

热门文章

  1. MODULE_DEVICE_TABLE【转】
  2. Kickstart+HTTP+DHCP+TFTP全自动批量安装部署Linux系统
  3. SilverLight 条码 扫描枪 MVVM(转载)
  4. 恢复出厂设置后itms注册失败_手机恢复出厂设置后,与新手机的区别已被确认,望大家相互转告!...
  5. python ** 运算符_Python语法基础(2)运算符
  6. Linux下SVN 命令操作手册
  7. Struts2 xml配置
  8. 通过SharedPreferences方式存储复杂数据
  9. 同一个tomcat部署多个项目导致启动失败
  10. Spring Cloud-honghu Cloud分布式微服务云系统--云架构代码结构构建