java 多線程下載文件並實時計算下載百分比(斷點續傳)

多線程下載文件

多線程同時下載文件即:在同一時間內經過多個線程對同一個請求地址發起多個請求,將須要下載的數據分割成多個部分,同時下載,每一個線程只負責下載其中的一部分,最後將每個線程下載的部分組裝起來便可。安全

涉及的知識及問題

  • 請求的數據怎麼拆分
  • 拆分完成後怎麼下載
  • 如何計算實時下載量

一.請求的數據怎麼拆分

 1 int blockSize =fileLength/threadCount; //計算每一個線程須要下的長度
 2     for(int i=0;i<threadCount;i++) {
 3         int startSize=i*blockSize; //當前線程須要下載的開始位置
 4         int endSize=(i+1)*blockSize-1;//當前線程須要下載的結束位置
 5         if(1+i==threadCount) { //最後一個線程的結尾賦值文件大小
 6             endSize=fileLength;
 7         }
 8         threadList[i]= new DownThread_1(filePath, fileUrl, "線程"+i, startSize, endSize);
 9         threadList[i].start();
10     }
11                 

二.拆分完成後怎麼下載

try {
            URL url = new URL(urlPath);
            HttpURLConnection coon = (HttpURLConnection) url.openConnection();
            coon.setRequestProperty("range","bytes="+startSize+"-"+endSize); //設置獲取下載資源的開始位置和結束位置
            coon.setConnectTimeout(5000);
            if(coon.getResponseCode()==206) {//響應碼   由於上面設置了range 全部響應碼是206再也不是200
                BufferedInputStream bi=new BufferedInputStream(coon.getInputStream());
                RandomAccessFile raf=new RandomAccessFile(filePath, "rwd"); //斷點續傳的關鍵
                raf.seek(startSize); //將寫入點移動到當前線程寫入開始位置
                byte b[]=new byte[1024];
                int len=0;
                while ((len=bi.read(b))>-1) { //循環寫入
                    raf.write(b, 0, len);
                    synchronized (DownUtile.class) {//此處涉及到變量同步
                        DownUtile.downLength=DownUtile.downLength+len; //計算當前下載了多少
                    }
                }
                raf.close();
                bi.close();
                System.out.println("thread"+threadName+"下載完成,開始位置"+startSize+",結束位置"+endSize);
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

三.如何計算實時下載量

    while ((len=bi.read(b))>-1) { //循環寫入
           raf.write(b, 0, len);
           synchronized (DownUtile.class) {//此處涉及到變量同步
                DownUtile.downLength=DownUtile.downLength+len; //計算當前下載了多少
           }
        }

    while(DownUtile.downOver) {
         Thread.sleep(500); //間隔0.5秒計算一下
         if(DownUtile.downLength==fileLength) {
             DownUtile.downOver=false;
             System.out.println("下載完成:100%");
         }else {
              System.out.println("已經下載了:"+((int) (float)DownUtile.downLength / (float) fileLength * 100)+"%");
         }
    }

上述方法中  用到了synchronized(類鎖),爲何用到類鎖,由於計算下載的參數在DownUtile類中,爲了保證這個參數在多線程中同步,需保證在執行累加操做時線程安全。服務器

 

下面貼上所有的代碼

 1 public class DownLoadUtile {
 2     public static String filePath="C:\\Users\\Administrator\\Desktop\\下載\\ deme.exe"; //文件保存地址
 3     public static String fileUrl="http://123.6.39.120/dlied1.qq.com/lol/dltools/LOL_V4.1.2.3-V4.1.2.4_PATCH_0_tgod_signed.exe?mkey=5cfc8d87dddd9a57&f=5844&cip=221.221.188.162&proto=http";//文件地址
 4     public static int threadCount=5; //線程數量
 5     public static int fileLength=0; //文件大小
 6     public static Thread [] threadList=new Thread[threadCount];
 7     
 8     public DownLoadUtile() {
 9         
10     }
11     public DownLoadUtile(int threadCount) {//有參構造
12         this.threadCount=threadCount;
13     }
14     
15     public static void main(String[] args) throws Exception {
16         URL url=new URL(fileUrl);
17         HttpURLConnection conn = (HttpURLConnection) url.openConnection(); //建立鏈接對象
18         conn.setConnectTimeout(5000);//請求超時時間
19         
20         int code = conn.getResponseCode();
21         System.out.println("服務器響應碼"+code);
22         if(code==200) {//響應正常
23             fileLength=conn.getContentLength(); //獲取文件大小
24             File file = new File(filePath);
25             if(!file.exists()) {
26                 file.createNewFile();
27             }
28             RandomAccessFile raf = new RandomAccessFile(filePath, "rwd"); //斷點續傳的關鍵
29             raf.setLength(fileLength);
30             
31             int blockSize =fileLength/threadCount; //計算每一個線程須要下的長度
32             for(int i=0;i<threadCount;i++) {
33                 int startSize=i*blockSize; //當前線程須要下載的開始位置
34                 int endSize=(i+1)*blockSize-1;//當前線程須要下載的結束位置
35                 if(1+i==threadCount) { //最後一個線程的結尾賦值文件大小
36                     endSize=fileLength;
37                 }
38                 threadList[i]= new DownThread_1(filePath, fileUrl, "線程"+i, startSize, endSize);
39                 threadList[i].start();
40             }
41             
42             while(DownUtile.downOver) {
43                 Thread.sleep(500); //間隔0.5秒計算一下
44                 if(DownUtile.downLength==fileLength) {
45                     DownUtile.downOver=false;
46                     System.out.println("下載完成:100%");
47                 }else {
48                     System.out.println("已經下載了:"+((int) (float)DownUtile.downLength / (float) fileLength * 100)+"%");
49                 }
50             }
51             
52         }else {
53             System.out.println("服務器響應失敗"+code);
54         }
55         
56     }

 

下載類多線程

 1 public class DownThread_1 extends Thread{
 2 
 3     private String filePath;
 4     private String urlPath;
 5     private String threadName;
 6     private int startSize;
 7     private int endSize;
 8     
 9     public DownThread_1(String filePath,String urlPath,String threadName,int startSize,int endSize) {
10         this.endSize=endSize;
11         this.startSize=startSize;
12         this.filePath=filePath;
13         this.urlPath=urlPath;
14         this.threadName=threadName;
15     }
16     @Override
17     public void run() {
18          try {
19             URL url = new URL(urlPath);
20             HttpURLConnection coon = (HttpURLConnection) url.openConnection();
21             coon.setRequestProperty("range","bytes="+startSize+"-"+endSize); //設置獲取下載資源的開始位置和結束位置
22             coon.setConnectTimeout(5000);
23             if(coon.getResponseCode()==206) {//響應碼   由於上面設置了range 全部響應碼是206再也不是200
24                 BufferedInputStream bi=new BufferedInputStream(coon.getInputStream());
25                 RandomAccessFile raf=new RandomAccessFile(filePath, "rwd"); //斷點續傳的關鍵
26                 raf.seek(startSize); //將寫入點移動到當前線程寫入開始位置
27                 byte b[]=new byte[1024];
28                 int len=0;
29                 while ((len=bi.read(b))>-1) { //循環寫入
30                     raf.write(b, 0, len);
31                     synchronized (DownUtile.class) {//此處涉及到變量同步
32                         DownUtile.downLength=DownUtile.downLength+len; //計算當前下載了多少
33                     }
34                 }
35                 raf.close();
36                 bi.close();
37                 System.out.println("thread"+threadName+"下載完成,開始位置"+startSize+",結束位置"+endSize);
38             }
39         } catch (MalformedURLException e) {
40             e.printStackTrace();
41         } catch (IOException e) {
42             e.printStackTrace();
43         }
44     }
45 
46 }

參數類dom

1 public class DownUtile {
2     
3     public static  int downLength=0;//已經下載了多少
4     
5     public static boolean downOver=true; //下載是否完成
6     
7 }
相關文章
相關標籤/搜索