三、多線程斷點續傳
多線程下載
原理:服務器CPU分配給每條線程的時間片相同,服務器帶寬平均分配給每條線程,所以客戶端開啓的線程越多,就能搶佔到更多的服務器資源
確定每條線程下載多少數據
發送http請求至下載地址String path = "http://192.168.2.102:8080/3.mp3"; URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setReadTimeout(5000); conn.setConnectTimeout(5000); conn.setRequestMethod("GET");
獲取文件總長度,然後創建長度一致的臨時文件
if(conn.getResponseCode() == 200){ //獲得服務器流中數據的長度 int length = conn.getContentLength(); //創建一個臨時文件存儲下載的數據 RandomAccessFile raf = new RandomAccessFile(getFileName(path), "rwd"); //設置臨時文件的大小 raf.setLength(length); raf.close();
確定線程下載多少數據
//計算每個線程下載多少數據 int blockSize = length / THREAD_COUNT;
計算每條線程下載數據的開始位置和結束位置
for(int id = 1; id <= 3; id++){ //計算每個線程下載數據的開始位置和結束位置 int startIndex = (id - 1) * blockSize; int endIndex = id * blockSize - 1; if(id == THREAD_COUNT){ endIndex = length; } //開啓線程,按照計算出來的開始結束位置開始下載數據 new DownLoadThread(startIndex, endIndex, id).start(); }
在開啓的子線程中進行下載
再次發送請求至下載地址,請求開始位置至結束位置的數據String path = "http://192.168.1.102:8080/editplus.exe"; URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setReadTimeout(5000); conn.setConnectTimeout(5000); conn.setRequestMethod("GET"); //向服務器請求部分數據 conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex); conn.connect();
下載請求到的數據,存放至臨時文件中
if(conn.getResponseCode() == 206){ InputStream is = conn.getInputStream(); RandomAccessFile raf = new RandomAccessFile(getFileName(path), "rwd"); //指定從哪個位置開始存放數據 raf.seek(startIndex); byte[] b = new byte[1024]; int len; while((len = is.read(b)) != -1){ raf.write(b, 0, len); } raf.close(); }
多線程斷點續傳
多線程下載步驟:
- 1.發送Http請求至下載地址
- 2.成功響應後獲取服務器流中的數據長度
- 3.創建一個臨時文件(RandomAccessFile)存儲下載的數據,給臨時文件設置大小
- 4.開啓循環,計算每個線程下載的數據長度,即下載數據的開始位置和結束位置
- 5.同時開啓線程,按照計算的位置開始下載
- 6.在線程中向服務器請求部分數據
- 7.將請求到的數據存放在臨時文件中,並指定從哪個位置存放數據
帶斷點續傳的多線程下載
定義一個int變量記錄每條線程下載數據的總長度,然後加上該線程下載的開始位置,
得到的結果就是下次下載時,該線程開始的位置,把下載位置記錄在緩存文件中步驟:
- 1每次下載都把新的下載位置寫入緩存文本文件中
- 2下次下載開始時,先讀取緩存文件中的值,得到的值就是該線程新的開始位置
3三條線程都下載完畢之後,刪除緩存文件(注意刪除過程要同步)
//開啓子線程進行屬於耗時操作的網絡下載 Thread t=new Thread(){ @Override public void run() { try { URL url=new URL(path); HttpURLConnection conn=(HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(5000); conn.setReadTimeout(5000); if(conn.getResponseCode()==200){ //得到數據資源的大小 int length=conn.getContentLength(); File file=new File(Environment.getExternalStorageDirectory(),"asd.rmvb"); //創建臨時文件,參數file,“rwd”決定了臨時文件的位置和權限 RandomAccessFile raf=new RandomAccessFile(file, "rwd"); //設置臨時文件的大小 raf.setLength(length); raf.close(); int size=length/threadcount; for(int i=0;i<threadcount;i++){ //計算每條線程下載開始的位置 int startindex=i*size; int endindex=(i+1)*size-1; if(i==threadcount-1){ endindex=length-1; } //開啓子線程下載 new MyThread(startindex, endindex, i).start(); } } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }
};
下面是子線程類
class MyThread extends Thread{ private int startindex; private int endindex; private int threadId; public MyThread(int startindex, int endindex, int threadId) { super(); this.startindex = startindex; this.endindex = endindex; this.threadId = threadId; } public void run(){ try { //創建記錄子線程的下載進程的文件 File progressfile=new File(Environment.getExternalStorageDirectory(),threadId+".txt"); if(progressfile.exists()){ FileInputStream is=new FileInputStream(progressfile); BufferedReader bufr=new BufferedReader(new InputStreamReader(is)); int progress=Integer.parseInt(bufr.readLine()); startindex+=progress; currentprogress+=progress; pb.setProgress(progress); Message msg=handler.obtainMessage(); handler.sendEmptyMessage(1); bufr.close(); } URL url=new URL(path); HttpURLConnection conn=(HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(5000); conn.setReadTimeout(5000); //分段請求網絡數據 conn.setRequestProperty("Range", "bytes="+startindex+"-"+endindex); if(conn.getResponseCode()==200){ InputStream is=conn.getInputStream(); byte[] b=new byte[1024]; int len=0; int total=0; File file=new File(Environment.getExternalStorageDirectory(),"asd.rmvb"); RandomAccessFile raf=new RandomAccessFile(file, "rwd"); raf.seek(startindex); while((len=is.read(b))!=-1){ raf.write(b,0,len); total+=len; currentprogress+=len; pb.setProgress(currentprogress); Message msg=handler.obtainMessage(); handler.sendEmptyMessage(1); //File progressfile=new File(threadId+".txt"); RandomAccessFile progressraf=new RandomAccessFile(progressfile, "rwd"); progressraf.write((total+"").getBytes()); progressraf.close(); } finishedthread++; synchronized (path) { if(finishedthread==threadcount){ for(int i=0;i<threadcount;i++){ File f=new File(threadId+".txt"); f.delete(); finishedthread=0; } } } } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }
}