多线程---多线程并发下载

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

 

posted @ 2017-12-12 21:43  黑土白云  阅读(1216)  评论(0编辑  收藏  举报