Java开发之多线程下载和断点续传

时间:2020-12-29 21:13:38

代码实现了多线程下载和断点续传功能

  1 import java.io.BufferedReader;
  2 import java.io.File;
  3 import java.io.FileInputStream;
  4 import java.io.FileOutputStream;
  5 import java.io.IOException;
  6 import java.io.InputStream;
  7 import java.io.InputStreamReader;
  8 import java.io.RandomAccessFile;
  9 import java.net.HttpURLConnection;
 10 import java.net.URL;
 11 
 12 import javax.print.attribute.standard.Finishings;
 13 
 14 public class MultiDownload {
 15 
 16     static int ThreadCount = 3;
 17     static int finishedThread = 0;
 18     //确定下载地址
 19     static String path = "http://192.168.13.13:8080/QQPlayer.exe";
 20     public static void main(String[] args) {
 21         
 22         //发送get请求,请求这个地址的资源
 23         try {
 24             URL url = new URL(path);
 25             HttpURLConnection conn = (HttpURLConnection) url.openConnection();
 26             conn.setRequestMethod("GET");
 27             conn.setConnectTimeout(5000);
 28             conn.setReadTimeout(5000);
 29             
 30             if(conn.getResponseCode() == 200){
 31                 //拿到所请求资源文件的长度
 32                 int length = conn.getContentLength();
 33                 
 34                 File file = new File("QQPlayer.exe");
 35                 //生成临时文件
 36                 RandomAccessFile raf = new RandomAccessFile(file, "rwd");
 37                 //设置临时文件的大小
 38                 raf.setLength(length);
 39                 raf.close();
 40                 //计算出每个线程应该下载多少字节
 41                 int size = length / ThreadCount;
 42                 
 43                 for (int i = 0; i < ThreadCount; i++) {
 44                     //计算线程下载的开始位置和结束位置
 45                     int startIndex = i * size;
 46                     int endIndex = (i + 1) * size - 1;
 47                     //如果是最后一个线程,那么结束位置写死
 48                     if(i == ThreadCount - 1){
 49                         endIndex = length - 1;
 50                     }
 51 //                    System.out.println("线程" + i + "的下载区间是:" + startIndex + "---" + endIndex);
 52                     new DownLoadThread(startIndex, endIndex, i).start();
 53                 }
 54             }
 55         } catch (Exception e) {
 56             // TODO Auto-generated catch block
 57             e.printStackTrace();
 58         }
 59     }
 60     
 61     
 62 }
 63 class DownLoadThread extends Thread{
 64     int startIndex;
 65     int endIndex;
 66     int threadId;
 67     
 68     public DownLoadThread(int startIndex, int endIndex, int threadId) {
 69         super();
 70         this.startIndex = startIndex;
 71         this.endIndex = endIndex;
 72         this.threadId = threadId;
 73     }
 74 
 75     @Override
 76     public void run() {
 77         //再次发送http请求,下载原文件
 78         try {
 79             File progressFile = new File(threadId + ".txt");
 80             //判断进度临时文件是否存在
 81             if(progressFile.exists()){
 82                 FileInputStream fis = new FileInputStream(progressFile);
 83                 BufferedReader br = new BufferedReader(new InputStreamReader(fis));
 84                 //从进度临时文件中读取出上一次下载的总进度,然后与原本的开始位置相加,得到新的开始位置
 85                 startIndex += Integer.parseInt(br.readLine());
 86                 fis.close();
 87             }
 88             System.out.println("线程" + threadId + "的下载区间是:" + startIndex + "---" + endIndex);
 89             HttpURLConnection conn;
 90             URL url = new URL(MultiDownload.path);
 91             conn = (HttpURLConnection) url.openConnection();
 92             conn.setRequestMethod("GET");
 93             conn.setConnectTimeout(5000);
 94             conn.setReadTimeout(5000);
 95             //设置本次http请求所请求的数据的区间
 96             conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);
 97             
 98             //请求部分数据,相应码是206
 99             if(conn.getResponseCode() == 206){
100                 //流里此时只有1/3原文件的数据
101                 InputStream is = conn.getInputStream();
102                 byte[] b = new byte[1024];
103                 int len = 0;
104                 int total = 0;
105                 //拿到临时文件的输出流
106                 File file = new File("QQPlayer.exe");
107                 RandomAccessFile raf = new RandomAccessFile(file, "rwd");
108                 //把文件的写入位置移动至startIndex
109                 raf.seek(startIndex);
110                 while((len = is.read(b)) != -1){
111                     //每次读取流里数据之后,同步把数据写入临时文件
112                     raf.write(b, 0, len);
113                     total += len;
114 //                    System.out.println("线程" + threadId + "下载了" + total);
115                     
116                     //生成一个专门用来记录下载进度的临时文件
117                     RandomAccessFile progressRaf = new RandomAccessFile(progressFile, "rwd");
118                     //每次读取流里数据之后,同步把当前线程下载的总进度写入进度临时文件中
119                     progressRaf.write((total + "").getBytes());
120                     progressRaf.close();
121                 }
122                 System.out.println("线程" + threadId + "下载完毕-------------------小志参上!");
123                 raf.close();
124                 
125                 MultiDownload.finishedThread++;
126                 synchronized (MultiDownload.path) {
127                     if(MultiDownload.finishedThread == MultiDownload.ThreadCount){
128                         for (int i = 0; i < MultiDownload.ThreadCount; i++) {
129                             File f = new File(i + ".txt");
130                             f.delete();
131                         }
132                         MultiDownload.finishedThread = 0;
133                     }
134                 }
135                 
136             }
137         } catch (Exception e) {
138             // TODO Auto-generated catch block
139             e.printStackTrace();
140         }
141     }
142 }