前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java---多线程断点下载

Java---多线程断点下载

作者头像
bear_fish
发布2018-09-19 16:07:27
1K0
发布2018-09-19 16:07:27
举报

http://blog.csdn.net/jwzhangjie/article/details/9772247

在上一章中我们实现了多线程下载功能,这里我们添加断点下载功能,防止下载过程中程序意外退出。具体代码如下:

[java] view plain copy

  1. package com.jwzhangjie;  
  2. /**
  3.  * 说明:
  4.  * 每一个线程下载的位置计算方式:
  5.  * 开始位置:
  6.  * (线程id - 1)*每一块大小
  7.  * 结束位置:
  8.  * (线程id*每一块大小) - 1 
  9.  *  ---注意有时候不一定能够整除,所以最后一个线程的结束位置应该是文件的末尾
  10.  *  
  11.  *  步骤:
  12.  *  1.本地创建一个大小跟服务器文件相同的临时文件
  13.  *  2.计算分配几个线程去下载服务器上的资源,知道每个线程下载文件的位置
  14.  *  3.开启三个线程,每一个线程下载对应位置的文件
  15.  *  4.如果所有的线程,都把自己的数据下载完毕后,服务器上的资源都被下载到本地了
  16.  *  
  17.  *  断点下载:
  18.  *  1.使用文件记录每一个线程的下载长度
  19.  *  2.每一个下载开始之前,读取文件,如果文件存在并且长度大于0,则取出长度
  20.  *  3.将每一个线程的起始位置+已经下载的长度
  21.  *  4.所有的线程下载完毕后,删除保存下载长度的文件
  22.  */
  23. import java.io.File;  
  24. import java.io.FileInputStream;  
  25. import java.io.InputStream;  
  26. import java.io.RandomAccessFile;  
  27. import java.net.HttpURLConnection;  
  28. import java.net.URL;  
  29. public class Demo {  
  30. public static String path = "http://192.168.5.103:8080/examples/downloader.exe";//"http://softdownload.hao123.com/hao123-soft-online-bcs/soft/Y/2013-07-18_YoudaoDict_baidu.alading.exe";  
  31. public static int threadCount = 3;  
  32. public static int runningThread = 3;  
  33. public static void main(String[] args) throws Exception{  
  34. //1.连接服务器,获取一个文件,获取文件的长度,在本地创建一个跟服务器一样大小的临时文件
  35.         URL url = new URL(path);  
  36.         HttpURLConnection conn = (HttpURLConnection)url.openConnection();  
  37.         conn.setConnectTimeout(5000);  
  38.         conn.setRequestMethod("GET");  
  39. int code = conn.getResponseCode();  
  40. if (code == 200) {  
  41. //服务器端返回的数据的长度,实际上就是文件的长度
  42. int length = conn.getContentLength();  
  43.             System.out.println("文件总长度:"+length);  
  44. //在客户端本地创建出来一个大小跟服务器端一样大小的临时文件
  45.             RandomAccessFile raf = new RandomAccessFile("setup.exe", "rwd");  
  46. //指定创建的这个文件的长度
  47.             raf.setLength(length);  
  48.             raf.close();  
  49. //假设是3个线程去下载资源。
  50. //平均每一个线程下载的文件大小.
  51. int blockSize = length / threadCount;  
  52. for (int threadId = 1; threadId <= threadCount; threadId++) {  
  53. //第一个线程下载的开始位置
  54. int startIndex = (threadId - 1) * blockSize;  
  55. int endIndex = threadId * blockSize - 1;  
  56. if (threadId == threadCount) {//最后一个线程下载的长度要稍微长一点
  57.                     endIndex = length;  
  58.                 }  
  59.                 System.out.println("线程:"+threadId+"下载:---"+startIndex+"--->"+endIndex);  
  60. new DownLoadThread(path, threadId, startIndex, endIndex).start();  
  61.             }  
  62.         }else {  
  63.             System.out.printf("服务器错误!");  
  64.         }  
  65.     }  
  66. /**
  67.      * 下载文件的子线程  每一个线程下载对应位置的文件
  68.      * @author jie
  69.      *
  70.      */
  71. public static class DownLoadThread extends Thread{  
  72. private int threadId;  
  73. private int startIndex;  
  74. private int endIndex;  
  75. /**
  76.          * @param path 下载文件在服务器上的路径
  77.          * @param threadId 线程Id
  78.          * @param startIndex 线程下载的开始位置
  79.          * @param endIndex  线程下载的结束位置
  80.          */
  81. public DownLoadThread(String path, int threadId, int startIndex, int endIndex) {  
  82. super();  
  83. this.threadId = threadId;  
  84. this.startIndex = startIndex;  
  85. this.endIndex = endIndex;  
  86.         }  
  87. @Override
  88. public void run() {  
  89. try {  
  90. //检查是否存在记录下载长度的文件,如果存在读取这个文件
  91.                 File tmp_file = new File(threadId+".txt");  
  92. if (tmp_file.exists() && tmp_file.length() > 0) {  
  93.                     FileInputStream fio = new FileInputStream(tmp_file);  
  94. byte[] temp = new byte[1024];  
  95. int len = fio.read(temp);  
  96.                     String downloadlen = new String(temp, 0, len);  
  97. int downloadInt = Integer.parseInt(downloadlen);  
  98.                     startIndex = downloadInt;//修改下载的真实的开始位置
  99.                     System.out.println("线程:"+threadId+"真实的下载位置:"+startIndex+"--->"+endIndex);  
  100.                     fio.close();  
  101.                 }  
  102.                 URL url = new URL(path);  
  103.                 HttpURLConnection conn = (HttpURLConnection)url.openConnection();  
  104.                 conn.setConnectTimeout(5000);  
  105.                 conn.setRequestMethod("GET");  
  106. //重要:请求服务器下载部分文件 指定文件的位置
  107.                 conn.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex);  
  108. //从服务器请求全部资源返回200 ok如果从服务器请求部分资源 返回 206 ok
  109. int code = conn.getResponseCode();  
  110.                 System.out.println("code:"+code);  
  111.                 InputStream is = conn.getInputStream();//已经设置了请求的位置,返回的是当前位置对应的文件的输入流
  112.                 RandomAccessFile raf = new RandomAccessFile("setup.exe", "rwd");  
  113. //随机写文件的时候从哪个位置开始写
  114.                 raf.seek(startIndex);//定位文件
  115. int len = 0;  
  116. byte[] buffer = new byte[1024];  
  117. int total = 0;//已经下载的数据长度
  118. while ((len = is.read(buffer)) != -1) {  
  119.                     RandomAccessFile file = new RandomAccessFile(threadId+".txt", "rwd");  
  120.                     raf.write(buffer, 0, len);  
  121.                     total += len;  
  122.                     file.write((""+(total+startIndex)).getBytes());  
  123.                     file.close();  
  124.                 }  
  125.                 is.close();  
  126.                 raf.close();  
  127.                 System.out.println("线程:"+threadId+"下载完毕");  
  128.             } catch (Exception e) {  
  129.                 e.printStackTrace();  
  130.             }finally{  
  131.                 runningThread--;  
  132. if (runningThread == 0) {//所有的线程执行完毕
  133. for (int i = 1; i <= threadCount; i++) {  
  134.                         File file = new File(i+".txt");  
  135.                         file.delete();  
  136.                     }  
  137.                     System.out.println("文件全部下载完毕!");  
  138.                 }  
  139.             }  
  140.         }  
  141.     }  
  142. }  

实验测试结果:

第一次下载:

[html] view plain copy

  1. 文件总长度:5562040  
  2. 线程:1下载:---0--->1854012  
  3. 线程:2下载:---1854013--->3708025  
  4. 线程:3下载:---3708026--->5562040  
  5. code:206  
  6. code:206  
  7. code:206  

第二次下载:

[html] view plain copy

  1. 文件总长度:5562040  
  2. 线程:1下载:---0--->1854012  
  3. 线程:2下载:---1854013--->3708025  
  4. 线程:3下载:---3708026--->5562040  
  5. 线程:1真实的下载位置:21504--->1854012  
  6. 线程:2真实的下载位置:1871421--->3708025  
  7. 线程:3真实的下载位置:3726458--->5562040  
  8. code:206  
  9. code:206  
  10. code:206  

下载完毕:

[html] view plain copy

  1. 文件总长度:5562040  
  2. 线程:1下载:---0--->1854012  
  3. 线程:2下载:---1854013--->3708025  
  4. 线程:3下载:---3708026--->5562040  
  5. 线程:2真实的下载位置:3512893--->3708025  
  6. 线程:3真实的下载位置:5268602--->5562040  
  7. 线程:1真实的下载位置:1677312--->1854012  
  8. code:206  
  9. code:206  
  10. code:206  
  11. 线程:1下载完毕  
  12. 线程:2下载完毕  
  13. 线程:3下载完毕  
  14. 文件全部下载完毕!  
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016年08月04日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档