zoukankan      html  css  js  c++  java
  • Java多线程断点下载

    欢迎访问个人博客:www.yyxxk.com

    多线程下载已经提高了下载的效率,但是当一些特殊情况发生的时候,我们需要对程序进行处理,这样效率会更高。比如,断电断网等造成下载中断,那么我们下一次又要重新开始下载,这样效率底下,所以我们可以考虑使用断点下载。其原理主要是把每次每个线程的下载状况(已经下载的位置)保存到文件,下次读取出来,从上一次下载的位置继续下载,这样就大大提高了下载的效率。

    效果:

    开始下载:

    下载过程中:

    下载过程中,系统临时文件保存已下载的位置:

    下载完毕,系统清楚记录下载位置的临时文件:

    附代码如下:

      1 import java.io.File;
      2 import java.io.FileInputStream;
      3 import java.io.InputStream;
      4 import java.io.RandomAccessFile;
      5 import java.net.HttpURLConnection;
      6 import java.net.URL;
      7 
      8 /**
      9  * 多线程断点下载示例
     10  * @author YUANYUAN
     11  *
     12  */
     13 public class Demo {
     14     //下载所使用的线程数
     15     private static int threadCount=3;
     16     //当前活动的线程数
     17     private static int activeThread;
     18 
     19     public static void main(String[] args) throws Exception{
     20         //请求服务器的路径
     21         String path="http://192.168.2.114:8080/sqlite.exe";
     22         //构造URL地址
     23         URL url=new URL(path);
     24         //打开连接
     25         HttpURLConnection conn=(HttpURLConnection) url.openConnection();
     26         //设置请求超时的时间
     27         conn.setConnectTimeout(5000);
     28         //设置请求方式
     29         conn.setRequestMethod("GET");
     30         //获取相应码
     31         int code=conn.getResponseCode();
     32         if (code==200) {//请求成功
     33             //获取请求数据的长度
     34             int length=conn.getContentLength();
     35             //在客户端创建一个跟服务器文件大小相同的临时文件
     36             RandomAccessFile raf=new RandomAccessFile("setup.exe", "rwd");
     37             //指定临时文件的长度
     38             raf.setLength(length);
     39             raf.close();
     40             //假设3个线程去下载资源
     41             //平均每一个线程要下载的文件的大小
     42             int blockSize=length/threadCount;
     43             for (int threadId = 1; threadId <= threadCount; threadId++) {
     44                 //当前线程下载数据的开始位置
     45                 int startIndex=blockSize*(threadId-1);
     46                 //当前线程下载数据的结束位置
     47                 int endIndex=blockSize*threadId-1;
     48                 //确定最后一个线程要下载数据的最大位置
     49                 if (threadId==threadCount) {
     50                     endIndex=length;
     51                 }
     52                 //显示下载数据的区间
     53                 System.out.println("线程【"+threadId+"】开始下载:"+startIndex+"---->"+endIndex);
     54                 //开启下载的子线程
     55                 new DownloadThread(path, threadId, startIndex, endIndex).start();
     56                 activeThread++;
     57                 System.out.println("当前活动的线程数:"+activeThread);
     58             }
     59             
     60         }else{//请求失败
     61             System.out.println("服务器异常,下载失败!");
     62         }
     63     }
     64     
     65     /**
     66      * 下载文件的子线程 每一个文件都下载对应的数据
     67      * @author YUANYUAN
     68      *
     69      */
     70     public static class DownloadThread extends Thread{
     71         private String path;
     72         private int threadId;
     73         private int startIndex;
     74         private int endIndex;
     75         
     76         /**
     77          * 构造方法
     78          * @param path 下载文件的路径
     79          * @param threadId 下载文件的线程
     80          * @param startIndex 下载文件开始的位置
     81          * @param endIndex 下载文件结束的位置
     82          */
     83         public DownloadThread(String path, int threadId, int startIndex,
     84                 int endIndex) {
     85             this.path = path;
     86             this.threadId = threadId;
     87             this.startIndex = startIndex;
     88             this.endIndex = endIndex;
     89         }
     90 
     91 
     92 
     93         @Override
     94         public void run() {
     95             //构造URL地址
     96             try {
     97                 
     98                 File tempFile=new File(threadId+".txt");
     99                 //检查记录是否存在,如果存在读取数据
    100                 if (tempFile.exists()) {
    101                     FileInputStream fis=new FileInputStream(tempFile);
    102                     byte[] temp=new byte[1024];
    103                     int length=fis.read(temp);
    104                     //读取到已经下载的位置
    105                     int downloadNewIndex=Integer.parseInt(new String(temp, 0, length));
    106                     //设置重新开始下载的开始位置
    107                     startIndex=downloadNewIndex;
    108                     fis.close();
    109                     //显示真实下载数据的区间
    110                     System.out.println("线程【"+threadId+"】真实开始下载数据区间:"+startIndex+"---->"+endIndex);
    111                 }
    112                 
    113                 URL url = new URL(path);
    114                 HttpURLConnection conn=(HttpURLConnection) url.openConnection();
    115                 conn.setConnectTimeout(5000);
    116                 conn.setRequestMethod("GET");
    117                 //设置请求属性,请求部分资源
    118                 conn.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex);
    119                 int code=conn.getResponseCode();
    120                 if (code==206) {//下载部分资源,正常返回的状态码为206
    121                     InputStream is=conn.getInputStream();//已经设置了请求的位置,所以返回的是对应的部分资源
    122                     //构建随机访问文件
    123                     RandomAccessFile raf=new RandomAccessFile("setup.exe", "rwd");
    124                     //设置 每一个线程随机写文件开始的位置
    125                     raf.seek(startIndex);
    126                     //开始写文件
    127                     int len=0;
    128                     byte[] buffer=new byte[1024];
    129                     //该线程已经下载数据的长度
    130                     int total=0;
    131                     
    132                     while((len=is.read(buffer))!=-1){//读取输入流
    133                         //记录当前线程已下载数据的长度
    134                         RandomAccessFile file=new RandomAccessFile(threadId+".txt","rwd");
    135                         raf.write(buffer,0,len);//写文件
    136                         total+=len;//更新该线程已下载数据的总长度
    137                         System.out.println("线程【"+threadId+"】已下载数据:"+(total+startIndex));
    138                         //将已下载数据的位置记录写入到文件
    139                         file.write((startIndex+total+"").getBytes());
    140                         file.close();
    141                     }
    142                     is.close();
    143                     raf.close();
    144                     //提示下载完毕
    145                     System.out.println("线程【"+threadId+"】下载完毕");
    146                 }
    147             } catch (Exception e) {
    148                 e.printStackTrace();
    149                 System.out.println("线程【"+threadId+"】下载出现异常!!");
    150             }finally{
    151                 //活动的线程数减少
    152                 activeThread--;
    153                 if (activeThread==0) {
    154                     for (int i = 1; i <= threadCount; i++) {
    155                         File tempFile=new File(i+".txt");
    156                         tempFile.delete();
    157                     }
    158                     System.out.println("下载完毕,已清除全部临时文件");
    159                 }
    160             }
    161             
    162         }
    163     }
    164 }
  • 相关阅读:
    开发中使用的一些小知识
    vue form表单验证
    团队作业8——第二次项目冲刺(Beta阶段)--第五天
    团队作业8——第二次项目冲刺(Beta阶段)--第四天
    团队作业8——第二次项目冲刺(Beta阶段)--第三天
    团队作业8——第二次项目冲刺(Beta阶段)--第二天
    团队作业8——第二次项目冲刺(Beta阶段)--第一天
    Beta版本冲刺计划及安排
    团队作业7——Alpha冲刺之事后诸葛亮
    团队作业6——展示博客(Alpha版本)
  • 原文地址:https://www.cnblogs.com/javayuan/p/4946685.html
Copyright © 2011-2022 走看看