java 多线程下载器_Java多线程的下载器(1)
實現了一個基于Java多線程的下載器,可提供的功能有:
1. 對文件使用多線程下載,并顯示每時刻的下載速度。
2. 對多個下載進行管理,包括線程調度,內存管理等。
一:單個文件下載的管理
1. 單文件下載類層次
首先簡要介紹一下單個文件下載管理的類層次:
來一張圖來表示。
為需要下載的文件創建一個Download類,Download負責管理該文件下載時的線程管理、文件管理、當前速度計算等操作。
根據線程的數目tNum,將該文件分為tNum段,每段為一個DownloadBlock。在實際下載的過程中,并不是一次把所有的東西下載完,而是每次下載固定size的一段Di。所以每個DownloadBlock又會分成n段。
為每個DownloadBlock申請一個線程DownloadThread。其主要作用就是每次下載一段Di,并將其寫入到文件中。
2. 單文件下載
對于單個下載,步驟如下
連接資源服務器,獲取資源信息,創建文件
切分資源,為每個線程分配固定的下載區域。
1)封裝下載的屬性
在建立下載之前,我們把每一次下載進行抽象封裝。
首先把URL、目標文件等封裝在一個DownloadConfig類中。
其中包含了4個屬性:
private URL url; //文件下載地址
private File file; //下載文件保存目標文件
private int nthread; //下載該文件需要的線程數
private int priority; //該下載的優先級
2)連接資源服務器,獲取資源信息,創建文件,并指定文件大小
length =config.getUrl().openConnection().getContentLength();
RandomAccessFilefile= new RandomAccessFile(config.getFile(), "rw"); //隨機讀取
file.setLength(length);
file.close();
3)切分資源,為每個線程分配固定的下載區域,并將當前的下載加入到隊列中
int size = length /config.getNthread();for(int i = 0; i < config.getNthread(); i++){int start = i *size;intlen;if(i == config.getNthread() - 1)
len= length -start;else len =size;//并將當前的下載加入到下載隊列中
addDownloadBlock(getDownloadBlock(start, len));
}
3)啟動線程進行下載
下載的步驟如下:
1. 創建緩存,創建連接。設置獲取資源數據的范圍,創建文件,并設置寫入位置
//創建緩存
byte[] b;if(block.getLength()
b= new byte[(int)block.getLength()];elseb= new byte[Constants.BYTES_READ];//創建連接。設置獲取資源數據的范圍,從startPos到endPos
URLConnection con = null;
con.setRequestProperty("Range", "bytes=" + block.getStart() + "-" + block.getStart()+block.getLength()-1);
RandomAccessFile file= new RandomAccessFile(block.getDownload().getConfig().getFile(), "rw");//創建RandomAccessFile
file.seek(block.getStart()); //從startPos開始寫入
2. 如果當前block的length大于0,則從URL資源處獲取固定大小的資源,并將其寫入到文件中。
3 .更新block塊的start,以及length,如果length大于0,繼續進行2,否則則表示當前block已經下載完畢,退出該線程。
InputStream in =block.getDownload().getConfig().getUrl().openStream();intn;//對該block內的文件進行下載,
while(count
long newLength = (block.getLength() - count) / 2;long newStart = block.getStart() + block.getLength() -newLength;
DownloadBlock newBlock=block.getDownload().getDownloadBlock(newStart, newLength);
block.setLength(block.getLength()-newLength);
block.getDownload().addDownloadBlock(newBlock);
}//寫入文件
n =in.read(b);if(n < 0){break;
}else if(count + n >block.getLength()){
file.write(b,0, (int)(block.getLength() -count));
count=block.getLength();
}else{
count+=n;
file.write(b,0, n);
}//set block count in download
if(n > 0){//統計每個block中已經下載的段的個數,用于計算當前下載的速度。
block.getDownload().setBlockCount(block.getStart(), count);
}
}
in.close();
file.close();
二 . 當前文件下載速度與進度計算
如第一個圖所表示的,每個Block中又分為了很多的段D1、D2、…Dn,因此當為 了計算當前下載的速度,需要將下載的段D的數量統計出來,這里使用了一個ConcurrentHashMap來保存每個block已經下載完成的段D的數目。其中key為每個block的start值,而value為該block已經下載完的段 D。
在當前時刻,我們需要統計當前Download已經下載完成段D的數量,然后再和上一時刻的相比較,則可以得出當前的下載速度。具體代碼見下:
class CheckSpeedTask extendsTimerTask{private static final Log log = LogFactory.getLog(CheckSpeedTask.class);privateDownload download;private ConcurrentHashMapblockCounts;private long speed = 0; //Byte/S
private long count = 0; //Total downloaded byte count
private long lastCount = 0;private long time = 0; //Check time
private long lastTime = 0;public CheckSpeedTask(Download download, long startTime, ConcurrentHashMapblockCounts){this.download =download;this.lastTime =startTime;this.blockCounts =blockCounts;
}
@Overridepublic voidrun() {try{
time=System.currentTimeMillis();
count= 0;//需要統計當前已經下載完成段D的數量。
for(longc : blockCounts.values()){
count+=c;
}
speed= (count -lastCount)/((time - lastTime)/1000);
log.debug(blockCounts.size()+ " threads are downloading " + download + ", cuttent is " + speed + "Byte/S, " + (count * 1.0)/download.getLength()*100 + "% downloaded");
download.setCount(count);
download.setSpeed(speed);
lastTime=time;
lastCount=count;
}catch(Exception e) {//TODO: handle exception
e.printStackTrace();
}
}
}
這樣我們就可以在Thread類的run()函數中,計算當前下載的速度
while(activeThreads.size() > 0 || blockQueue.size() > 0){
Thread.sleep(1000);
checkSpeed();
}
原文:http://blog.csdn.net/zhzhl202/article/details/7521377
總結
以上是生活随笔為你收集整理的java 多线程下载器_Java多线程的下载器(1)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 判断日期周几_Java 输入一
- 下一篇: java美元兑换,(Java实现) 美元