zoukankan      html  css  js  c++  java
  • 多线程---多线程并发下载

    1.

    结果:

    133169
    线程0开始下载
    线程1开始下载
    线程2开始下载
    线程_1的下载起点是 44389 下载终点是: 88777
    线程_0的下载起点是 0 下载终点是: 44388
    线程_2的下载起点是 88778 下载终点是: 133168
    线程2下载完毕
    线程1下载完毕
    线程0下载完毕

      1 package ck.cn;
      2 
      3 import java.io.File;
      4 import java.io.InputStream;
      5 import java.io.RandomAccessFile;
      6 import java.net.HttpURLConnection;
      7 import java.net.URL;
      8 
      9 /**
     10  * 多线程下载 
     11  * 
     12  *
     13  */
     14 public class MultiThreadDown {
     15     private String path = "";
     16     private String targetFilePath="";  //下载文件存放目录
     17     private int threadCount = 3;    //线程数量
     18 
     19     /**
     20      * 构造方法 
     21      * @param path 要下载文件的网络路径
     22      * @param targetFilePath 保存下载文件的目录
     23      * @param threadCount 开启的线程数量,默认为 3
     24      */
     25     public MultiThreadDown(String path, String targetFilePath, int threadCount) {
     26         this.path = path;
     27         this.targetFilePath = targetFilePath;
     28         this.threadCount = threadCount;
     29     }
     30 
     31     /**
     32      * 下载文件
     33      */
     34     public void download() throws Exception{
     35         //连接资源
     36         URL url = new URL(path);
     37         HttpURLConnection connection = (HttpURLConnection) url.openConnection();
     38         connection.setRequestMethod("GET");
     39         connection.setConnectTimeout(10000);
     40 
     41         int code = connection.getResponseCode();
     42         if(code == 200){
     43             //获取资源大小
     44             int connectionLength = connection.getContentLength();
     45             System.out.println(connectionLength);
     46             //在本地创建一个与资源同样大小的文件来占位
     47             RandomAccessFile randomAccessFile = new RandomAccessFile(new File(targetFilePath,getFileName(url)), "rw");
     48             randomAccessFile.setLength(connectionLength);
     49             /*
     50              * 将下载任务分配给每个线程
     51              */
     52             int blockSize = connectionLength/threadCount;//计算每个线程理论上下载的数量.
     53             for(int threadId = 0; threadId < threadCount; threadId++){//为每个线程分配任务
     54                 int startIndex = threadId * blockSize; //线程开始下载的位置
     55                 int endIndex = (threadId+1) * blockSize -1; //线程结束下载的位置
     56                 if(threadId == (threadCount - 1)){  //如果是最后一个线程,将剩下的文件全部交给这个线程完成
     57                     endIndex = connectionLength - 1;
     58                 }
     59 
     60                 new DownloadThread(threadId, startIndex, endIndex).start();//开启线程下载
     61 
     62             }
     63         }
     64 
     65     }
     66 
     67     //下载的线程
     68     private class DownloadThread extends Thread{
     69 
     70         private int threadId;
     71         private int startIndex;
     72         private int endIndex;
     73 
     74         public DownloadThread(int threadId, int startIndex, int endIndex) {
     75             this.threadId = threadId;
     76             this.startIndex = startIndex;
     77             this.endIndex = endIndex;
     78         }
     79 
     80         @Override
     81         public void run() {
     82             System.out.println("线程"+ threadId + "开始下载");
     83             try {
     84                 //分段请求网络连接,分段将文件保存到本地.
     85                 URL url = new URL(path);
     86 
     87                 //加载下载位置的文件
     88                 File downThreadFile = new File(targetFilePath,"downThread_" + threadId+".dt");
     89                 RandomAccessFile downThreadStream = null;
     90                 if(downThreadFile.exists()){//如果文件存在
     91                     downThreadStream = new RandomAccessFile(downThreadFile,"rwd");
     92                     String startIndex_str = downThreadStream.readLine();
     93                     if(null==startIndex_str||"".equals(startIndex_str)){  //网友 imonHu 2017/5/22  
     94                         this.startIndex=startIndex;  
     95                     }else{  
     96                         this.startIndex = Integer.parseInt(startIndex_str)-1;//设置下载起点  
     97                     }
     98                 }else{
     99                     downThreadStream = new RandomAccessFile(downThreadFile,"rwd");
    100                 }
    101 
    102                 HttpURLConnection connection = (HttpURLConnection) url.openConnection();
    103                 connection.setRequestMethod("GET");
    104                 connection.setConnectTimeout(10000);
    105 
    106                 //设置分段下载的头信息。  Range:做分段数据请求用的。格式: Range bytes=0-1024  或者 bytes:0-1024
    107                 connection.setRequestProperty("Range", "bytes="+ startIndex + "-" + endIndex);
    108 
    109                 System.out.println("线程_"+threadId + "的下载起点是 " + startIndex + "  下载终点是: " + endIndex);
    110 
    111                 if(connection.getResponseCode() == 206){//200:请求全部资源成功, 206代表部分资源请求成功
    112                     InputStream inputStream = connection.getInputStream();//获取流
    113                     RandomAccessFile randomAccessFile = new RandomAccessFile(new File(targetFilePath,getFileName(url)), "rw");//获取前面已创建的文件.
    114                     randomAccessFile.seek(startIndex);//文件写入的开始位置.
    115 
    116 
    117                     /*
    118                      * 将网络流中的文件写入本地
    119                      */
    120                     byte[] buffer = new byte[1024];
    121                     int length = -1;
    122                     int total = 0;//记录本次下载文件的大小
    123                     while((length = inputStream.read(buffer)) > 0){
    124                         randomAccessFile.write(buffer, 0, length);
    125                         total += length;
    126                         /*
    127                          * 将当前现在到的位置保存到文件中
    128                          */
    129                         downThreadStream.seek(0);
    130                         downThreadStream.write((startIndex + total + "").getBytes("UTF-8"));
    131                     }
    132 
    133                     downThreadStream.close();
    134                     inputStream.close();
    135                     randomAccessFile.close();                   
    136                     cleanTemp(downThreadFile);//删除临时文件
    137                     System.out.println("线程"+ threadId + "下载完毕");
    138                 }else{
    139                     System.out.println("响应码是" +connection.getResponseCode() + ". 服务器不支持多线程下载");
    140                 }
    141             } catch (Exception e) {
    142                 e.printStackTrace();
    143             }
    144 
    145         }
    146     }
    147 
    148     //删除线程产生的临时文件
    149     private synchronized void cleanTemp(File file){
    150         file.delete();
    151     }
    152 
    153     //获取下载文件的名称
    154     private String getFileName(URL url){
    155         String filename = url.getFile();
    156         return filename.substring(filename.lastIndexOf("/")+1);
    157     }
    158 
    159     public static void main(String[] args) {
    160         String path = "http://img07.tooopen.com/images/20170316/tooopen_sy_201956178977.jpg";
    161         String targetFilePath="d:/";  //下载文件存放目录
    162         int threadCount = 3;
    163         try {
    164             new MultiThreadDown(path, targetFilePath, threadCount).download();
    165 
    166         } catch (Exception e) {
    167             e.printStackTrace();
    168         }
    169     }
    170 }
    View Code
  • 相关阅读:
    ASP.NET多线程下使用HttpContext.Current为null解决方案
    Pig性能优化
    重温设计模式之前言
    MVC4+WebApi+Redis Session共享练习(下)
    C#中对象的输出
    CYQ.Data 支持WPF相关的数据控件绑定.Net获取iis版本
    java版微信公众平台自定义菜单创建代码实现
    android动画特效之解决解决移动后闪烁现象,解决输入法弹出后位置回复原状,解决两个动画叠加
    VMware 11安装Mac OS X 10.10 及安装Mac Vmware Tools(超详细),以及动态调整虚拟机硬盘大小
    三个API:开启、关闭、关闭线程重定向
  • 原文地址:https://www.cnblogs.com/bravolove/p/8029904.html
Copyright © 2011-2022 走看看