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)使用HttpRange頭字段指定每條線程從文件的什么位置開始下載,下載到什么位置為止,

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

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

 

  (4)保存文件,使用RandomAccessFile類指定每條線程從本地文件的什么位置開始寫入數據。

RandomAccessFile threadfile = new RandomAccessFile("QQWubiSetup.exe ","rwd");

threadfile.seek(2097152);//從文件的什么位置開始寫入數據

/** 
*多線程下載,UI更新類
*@author young
* */
public class MultiThreadDownload extends Thread{
private static final String TAG = "MultiThreadDownload";
/**每一個線程需要下載的大小 */
private int blockSize;
/*** 線程數量<br> 默認為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)  //當前位置小於結束位置  繼續下載                      {                          int len = bis.read(buf,0,BUFF_SIZE);                          if(len==-1)   //下載完成                            {                               break;                          }                          rAccessFile.write(buf,0,len);                          curPosition = curPosition +len;                          if(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下載


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



Android多線程下載 android多線程下載 android 多線程下載 Android——單、多線程下載 Android多線程下載(一) android多線程下載2 Android 多線程下載 Android -- 多線程下載 android 多線程下載 android --多線程下載
 
粤ICP备14056181号  © 2014-2021 ITdaan.com