android --多線程下載過程分析

來源:互聯網
上載者:User

android --多線程下載過程分析

多線程下載檔案的過程是:

(1)首先獲得下載檔案的長度,然後設定本地檔案的長度。

HttpURLConnection.getContentLength();//擷取下載檔案的長度

RandomAccessFile file = new RandomAccessFile("QQSetup.exe","rwd");

file.setLength(filesize);//設定本地檔案的長度

 

(2)根據檔案長度和線程數計算每條線程下載的資料長度和下載位置。

如:檔案的長度為6M,線程數為3,那麼,每條線程下載的資料長度為2M,每條線程開始下載的位置如所示。

例如10M大小,使用3個線程來下載,

線程下載的資料長度 (10%3 == 0 ? 10/3:10/3+1) ,第1,2個線程下載長度是4M,第三個線程下載長度為2M

下載開始位置:線程id*每條線程下載的資料長度 = ?

下載結束位置:(線程id+1)*每條線程下載的資料長度-1=?

 

(3)使用Http的Range頭欄位指定每條線程從檔案的什麼位置開始下載,下載到什麼位置為止,

如:指定從檔案的2M位置開始下載,下載到位置(4M-1byte)為止

代碼如下:HttpURLConnection.setRequestProperty("Range", "bytes=2097152-4194303");

 

(4)儲存檔案,使用RandomAccessFile類指定每條線程從本地檔案的什麼位置開始寫入資料。

RandomAccessFilethreadfile= newRandomAccessFile("QQWubiSetup.exe ","rwd");

threadfile.seek(2097152);//從檔案的什麼位置開始寫入資料

 

/**  *多線程下載,UI更新類   *@author young  * */  public class MultiThreadDownload extends Thread{      private static final String TAG = "MultiThreadDownload";      /**每一個線程需要下載的大小 */      private int blockSize;      /*** 線程數量 預設為5個線程下載*/      private int threadNum = 5;      /*** 檔案大小 */      private int fileSize;      /** * 已經下載多少 */      private int downloadSize;      /**檔案的url,線程編號,檔案名稱*/      private String UrlStr,ThreadNo,fileName;      /***儲存的路徑*/      private String savePath;      /**下載的百分比*/      private int downloadPercent = 0;      /**下載的 平均速度*/      private int downloadSpeed = 0;      /**下載用的時間*/      private int usedTime = 0;      /**目前時間*/      private long curTime;      /**是否已經下載完成*/      private boolean completed = false;      private Handler handler ;      /**      * 下載的建構函式        * @param url  請求下載的URL      * @param handler   UI更新使用      * @param savePath  儲存檔案的路徑      */      public MultiThreadDownload(Handler handler,String url,String savePath)      {          this.handler = handler;          this.UrlStr = url;          this.savePath = savePath;          Log.e(TAG, toString());      }            @Override      public void run() {                    FileDownloadThread[] fds = new FileDownloadThread[threadNum];//設定線程數量          try {              URL url = new URL(UrlStr);              URLConnection conn = url.openConnection();              fileSize = conn.getContentLength();                            this.fileName = FileUtil.getFileName(UrlStr);              //只建立一個檔案,saveFile下載內容              File saveFile = new File(savePath+"/"+fileName);              Log.e(TAG, "檔案一共:"+fileSize+" savePath "+savePath+"  fileName  "+fileName);                            RandomAccessFile accessFile = new RandomAccessFile(saveFile,"rwd");              //設定本地檔案的長度和下載檔案相同                 accessFile.setLength(fileSize);                accessFile.close();              //Handler更新UI,發送訊息              sendMsg(FileUtil.startDownloadMeg);              //每塊線程下載資料              blockSize = ((fileSize%threadNum)==0)?(fileSize/threadNum):(fileSize/threadNum+1);              Log.e(TAG, "每個線程分別下載 :"+blockSize);                            for (int i = 0; i < threadNum; i++) {                  int curThreadEndPosition = (i+1)!=threadNum ? ((i+1)*blockSize-1) : fileSize;                  FileDownloadThread fdt = new FileDownloadThread(url, saveFile, i*blockSize, curThreadEndPosition);                  fdt.setName("thread"+i);                  fdt.start();                  fds[i]=fdt;              }              /**              * 擷取資料,更新UI,直到所有下載線程都下載完成。              */              boolean finished = false;              //開始時間,放在迴圈外,求解的usedTime就是總時間              long startTime = System.currentTimeMillis();              while(!finished)              {                  downloadSize = 0;                  finished = true;                  for (int i = 0; i < fds.length; i++) {                      downloadSize+= fds[i].getDownloadSize();                      if(!fds[i].isFinished())                      {                          finished = false;                      }                  }                  downloadPercent = (downloadSize*100)/fileSize;                  curTime = System.currentTimeMillis();                  System.out.println("curTime = "+curTime+" downloadSize = "+downloadSize+" usedTime "+(int) ((curTime-startTime)/1000));                  usedTime = (int) ((curTime-startTime)/1000);                                    if(usedTime==0)usedTime = 1;                    downloadSpeed = (downloadSize/usedTime)/1024;                  sleep(1000);/*1秒鐘重新整理一次介面*/                  sendMsg(FileUtil.updateDownloadMeg);              }              Log.e(TAG, "下載完成");              completed = true;              sendMsg(FileUtil.endDownloadMeg);          } catch (Exception e) {              Log.e(TAG, "multi file error  Exception  "+e.getMessage());              e.printStackTrace();          }          super.run();      }      /**      * 得到檔案的大小      * @return      */      public int getFileSize()      {          return this.fileSize;      }      /**      * 得到已經下載的數量      * @return      */      public int getDownloadSize()      {          return this.downloadSize;      }      /**      * 擷取下載百分比      * @return      */      public int getDownloadPercent(){          return this.downloadPercent;      }     /**     * 擷取下載速度     * @return     */      public int getDownloadSpeed(){          return this.downloadSpeed;      }      /**      * 修改預設線程數      * @param threadNum      */      public void setThreadNum(int threadNum){          this.threadNum = threadNum;      }      /**      * 分塊下載完成的標誌      * @return      */      public boolean isCompleted(){          return this.completed;      }      @Override      public String toString() {          return "MultiThreadDownload [threadNum=" + threadNum + ", fileSize="                  + fileSize + ", UrlStr=" + UrlStr + ", ThreadNo=" + ThreadNo                  + ", savePath=" + savePath + "]";      }            /**      * 發送訊息,使用者提示      * */      private void sendMsg(int what)      {          Message msg = new Message();          msg.what = what;          handler.sendMessage(msg);      } 
public class FileDownloadThread extends Thread{      private static final String TAG = "FileDownloadThread";      /**緩衝區 */      private static final int BUFF_SIZE = 1024;      /**需要下載的URL*/      private URL url;      /**緩衝的FIle*/      private File file;      /**開始位置*/      private int startPosition;      /**結束位置*/      private int endPosition;      /**當前位置*/      private int curPosition;      /**完成*/      private boolean finished = false;      /**已經下載多少*/      private int downloadSize = 0;            /***      * 區塊檔案下載,可以建立多線程模式      * @param url   下載的URL      * @param file  下載的檔案      * @param startPosition 開始位置      * @param endPosition   結束位置      */      public FileDownloadThread(URL url, File file, int startPosition,              int endPosition) {          this.url = url;          this.file = file;          this.startPosition = startPosition;          this.curPosition = startPosition;          this.endPosition = endPosition;          Log.e(TAG, toString());      }            @Override      public void run() {          BufferedInputStream bis = null;          RandomAccessFile rAccessFile = null;          byte[] buf = new byte[BUFF_SIZE];          URLConnection conn = null;          try {              conn = url.openConnection();              conn.setConnectTimeout(10000);//設定逾時              conn.setReadTimeout(10000);              conn.setAllowUserInteraction(true);                      System.out.println(this.getName()+" startPosition "+startPosition+" endPosition "+endPosition);                      conn.setRequestProperty("Range", "bytes="+(startPosition)+"-"+endPosition);  //取剩餘未下載的                      rAccessFile = new RandomAccessFile(file,"rwd");//讀寫                       //設定從什麼位置開始寫入資料                       rAccessFile.seek(startPosition);                      bis = new BufferedInputStream(conn.getInputStream(), BUFF_SIZE);                      while(curPosition endPosition)                          {   //如果下載多了,則減去多餘部分                              System.out.println("  curPosition > endPosition  !!!!");                              int extraLen = curPosition-endPosition;                              downloadSize += (len-extraLen+1);                          }else{                              downloadSize+=len;                          }                      }                      this.finished = true;  //當前階段下載完成              Log.e(TAG, "當前"+this.getName()+"下載完成");          } catch (Exception e) {              Log.e(TAG, "download error Exception "+e.getMessage());              e.printStackTrace();          }finally{              //關閉流              FileUtil.closeInputStream(bis);              try {                  rAccessFile.close();              } catch (IOException e) {                  // TODO Auto-generated catch block                  Log.e("AccessFile", "AccessFile IOException "+e.getMessage());              }          }          super.run();      }            /**      * 是否完成當前段下載完成      * @return      */      public boolean isFinished() {          return finished;      }      /**      * 已經下載多少      * @return      */      public int getDownloadSize() {          return downloadSize;      }        @Override      public String toString() {          return "FileDownloadThread [url=" + url + ", file=" + file                  + ", startPosition=" + startPosition + ", endPosition="                  + endPosition + ", curPosition=" + curPosition + ", finished="                  + finished + ", downloadSize=" + downloadSize + "]";      }  

多線程下載是分段下載,建立儲存一個檔案,子線程分別通過RandomAccessFile類進行寫入操作。

 


樣本源碼:demo下載

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.