爲了更快的下載資源,我們可以採用多線程的方式來實現文件的下載。
多線程文件下載的基本原理如下:使用HttpURLConnection獲取與資源指定URL的鏈接,httpurlconnection對象通過getContentLength可以獲取下載文件的長度,等到需要下載的文件的長度以後,在本地創建一個與下載文件長度相同的文件,然後通過RandomAccessFile對文件進行寫入操作,那麼如何加入多線程呢?思想是將文件分爲幾個部分,每一個線程完成每一個部分的下載和文件寫入操作。通過RandomAccessFile可以實現文件的隨機訪問,因此每個線程都可以講自己負責下載的內容寫到文件中指定的位置,而不用擔心文件中內容出現錯位。
下面是線程類的代碼
public class MulThreadDownLoad extends Thread {
private String path;
private File file;
private int tasksize;
private int threadid;
public MulThreadDownLoad(String path ,File file , int tasksize, int threadid){
this.path = path; //文件路徑
this.file = file; //文件
this.tasksize = tasksize; //單個線程的下載量
this.threadid = threadid; //線程的id
}
@Override
public void run() {
try {
int startPoint = threadid * tasksize; //每條線程寫入文件的起點
int endPoint = (threadid + 1 ) * tasksize -1 ; //每條線程寫入文件的終點
RandomAccessFile accessFile = new RandomAccessFile(file,"rwd");
accessFile.seek(startPoint);
HttpURLConnection con = (HttpURLConnection) new URL(path).openConnection();
con.setConnectTimeout(500);
con.setRequestMethod("GET");
// con.setRequestProperty("Range", "bytes="+startPoint+"-"+endPoint); 如果設置了Range字段,那麼響應碼是206而不是200
if(con.getResponseCode() == 200){
InputStream ins = con.getInputStream();
ins.skip(startPoint); //跳過前面線程已經下載過的內容,
byte [] buffer = new byte [1024];
int length = 0;
while((length = ins.read(buffer)) != -1 ){ //將讀取的字節寫入文件中
accessFile.write(buffer);
}
accessFile.close();
ins.close();
}
System.out.print((threadid +1 )+"線程已經下載完成 :");
System.out.println("bytes = "+startPoint+"-"+endPoint);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
下面這個是測試類,在測試類中,指定了文件下載的路徑,通過文件的路徑,獲取了文件名
public class MulThreadDownLoadTest {
private File file ;
public static void main(String args []) throws Exception{
String path = "http://localhost:8080/test/jj.jpg";
new MulThreadDownLoadTest().download(path,3);
}
/*
* @path 指定下載的目標路徑
* @threaCount 指定需要多少個線程進行下載
*/
public void download(String path, int threadCount ) throws Exception{
URL url = new URL(path);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
con.setConnectTimeout(500);
if(con.getResponseCode() == 200){
int ContentLength = con.getContentLength();//獲取響應的長度
String fileName = getFileName(path); //獲取文件名
file = new File(fileName);
System.out.println("下載文件大小"+ContentLength);
RandomAccessFile accessFile = new RandomAccessFile(file,"rwd"); //rwd 表示對文件內容的每個更新都同步寫入到底層存儲設備。
accessFile.setLength(ContentLength);
accessFile.close();
//計算每個線程的下載長度爲多少
int tasksize = (ContentLength%threadCount == 0 ? ContentLength/threadCount : ContentLength/threadCount+ 1);
for(int threadid = 0; threadid < threadCount ;threadid++ ){
new MulThreadDownLoad(path,file,tasksize,threadid).start();
}
}
}
public static String getFileName(String path){
return path.substring(path.lastIndexOf("/")+1);
}
}
文章參考
傳智播客培訓視頻
http://www.cnblogs.com/tiantianbyconan/archive/2013/02/20/2919132.html