package cn.me.test;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* 多線程下載
* 1:使用RandomAccessFile在任意的位置寫入資料。
* 2:需要計算第一個執行緒下載的資料量,可以平均分配。如果不夠平均時,
* 則直接最後一個執行緒處理相對較少的數據
* 3:必須在下載之前準備好相同大小的文件,透過文件頭取得
*/
public class MultiThreadDownload {
public static void main(String[] args) throws Exception {
//1:聲明檔名和下載的位址
String fileName = "aa.rar";
String urlStr = "http://localhost:7777/day18";
//2:聲明Url
URL url = new URL(urlStr+"/"+fileName);
//3:取得連接
HttpURLConnection con =
(HttpURLConnection) url.openConnection();
//4:設定請求方式
con.setRequestMethod("GET");
//5:取得請求頭,即檔案的長度
int length = con.getContentLength();//取得下載檔案的長度,以計算每個執行緒應該下載的資料量。
//6:在指定的目錄下,建立一個同等大小的文件
RandomAccessFile file = new RandomAccessFile("d:/a/"+fileName, "rw");//建立一個大小相同的檔案。
//7:設定檔案大小,佔位
file.setLength(length);//設定檔大小。
file.close();
//8:定義執行緒個數
int size = 3;
//9:計算每個執行緒應該下載多少位元組的數據,如果剛好整除則最好,否則加1
int block = length/size==0?length/size:length/size+1;//計算每個執行緒應該下載的資料量。
System.err.println("每個執行緒應該下載:"+block);
//10:執行三個執行緒並計算從哪個位元組開始到哪一個位元組結束
for(int i=0;i<size;i++){
int start = i*block;
int end = start+(block-1);//計算每一個執行緒的開始和結束位元組。
System.err.println(i+"="+start+","+end);
new MyDownThread(fileName, start, end,url).start();
}
}
static class MyDownThread extends Thread{
//定義檔名
private String fileName;
//定義從何地開始下載
private int start;
//定義下載到哪一個位元組
private int end;
private URL url;
public MyDownThread(String fileName,int start,int end,URL url){
this.fileName=fileName;
this.start=start;
this.end=end;
this.url=url;
}
@Override
public void run() {
try{
//11:開始下載
HttpURLConnection con =
(HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
//12:設定分段下載的請求頭
con.setRequestProperty("Range","bytes="+start+"-"+end);//設定從伺服器上讀取的檔案區塊。
//13:開始下載,需要判斷206
if(con.getResponseCode()==206){//存取成功,則傳回的狀態碼為206。
InputStream in = con.getInputStream();
//14:宣告隨機寫入檔案對象,注意rwd是指即時將資料寫到檔案中,而不使用快取區
RandomAccessFile out = new RandomAccessFile("d:/a/"+fileName,"rwd");
out.seek(start);//設定從檔案的某個位置開始寫入資料。
byte[] b=new byte[1024];
int len = 0;
while((len=in.read(b))!=-1){
out.write(b,0,len);
}
out.close();
in.close();
}
System.err.println(this.getName()+"執行完成");
}catch(Exception e){
throw new RuntimeException(e);
}
}
}
}