/**
* author
* date
*/
annegu做了一個簡單的Http多線程的下載程序
這個程序的功能
下載的方法是download()
/**
*/
public String download(String urlStr
this
long contentLength =
CountDownLatch latch = new CountDownLatch(threadNum);
long[] startPos = new long[threadNum];
long endPos =
try {
// 從url中獲得下載的文件格式與名字
this
this
URLConnection con = url
setHeader(con);
// 得到content的長度
contentLength = con
// 把context分為threadNum段的話
this
// 第一步
startPos = setThreadBreakpoint(fileDir
//第二步
ExecutorService exec = Executors
for (int i =
// 創建子線程來負責下載數據
startPos[i] += threadLength * i;
/**//*設置子線程的終止位置
最後一個線程的終止位置即為下載內容的長度*/
if (i == threadNum
endPos = contentLength;
} else {
endPos = threadLength * (i +
}
// 開啟子線程
ChildThread thread = new ChildThread(this
childThreads[i] = thread;
exec
}
try {
// 等待CountdownLatch信號為
latch
exec
// 第三步
tempFileToTargetFile(childThreads);
} catch (InterruptedException e) {
e
}
}
首先來看最主要的步驟
首先從url中提取目標文件的名稱
在這個例子中
好了
ChildThread就是子線程
這個CountDownLatch是做什麼用的呢?
現在我們整理一下思路
CountDownLatch用來同步主線程
對每個子線程來說
/**
*author by
*/
public class ChildThread extends Thread {
public static final int STATUS_HASNOT_FINISHED =
public static final int STATUS_HAS_FINISHED =
public static final int STATUS_HTTPSTATUS_ERROR =
private DownloadTask task;
private int id;
private long startPosition;
private long endPosition;
private final CountDownLatch latch;
private File tempFile = null;
//線程狀態碼
private int status = ChildThread
public ChildThread(DownloadTask task
super();
this
this
this
this
this
try {
tempFile = new File(this
if(!tempFile
tempFile
}
} catch (IOException e) {
e
}
}
public void run() {
System
HttpURLConnection con = null;
InputStream inputStream = null;
BufferedOutputStream outputStream = null;
int count =
long threadDownloadLength = endPosition
try {
outputStream = new BufferedOutputStream(new FileOutputStream(tempFile
} catch (FileNotFoundException e
e
}
③ for(;;){
④ startPosition += count;
try {
//打開URLConnection
con = (HttpURLConnection) task
setHeader(con);
con
//設置連接超時時間為
⑤ con
//設置讀取數據超時時間為
con
if(startPosition < endPosition){
//設置下載數據的起止區間
con
+ endPosition);
System
System
//判斷http status是否為HTTP/
//如果不是以上兩種狀態
⑥ if (con
&& con
System
+ con
+ con
status = ChildThread
this
outputStream
con
System
untDown();
break;
}
inputStream = con
int len =
byte[] b = new byte[
while ((len = inputStream
outputStream
count += len;
//每讀滿
if(count %
⑦ outputStream
}
}
System
if(count >= threadDownloadLength){
hasFinished = true;
}
⑧ outputStream
outputStream
inputStream
con
}
System
untDown();
break;
} catch (IOException e) {
try {
⑨ outputStream
⑩ TimeUnit
} catch (InterruptedException e
e
} catch (IOException e
e
}
continue;
}
}
}
}
在ChildThread的構造方法中
現在讓我們來看看從網絡中讀數據是怎麼讀的
private void setHeader(URLConnection con) {
con
con
con
con
con
con
con
con
con
con
}
另外
這裡對超時的發生
連接建立好之後
a)
b)
c)
d)
e)
f)
g)
在這些狀態裡面
假設一切正常
public synchronized int read(byte b[]
我們的目標是要把目標地址的內容下載下來
OutputStream的write方法和上面InputStream的read方法有類似的參數
public synchronized void write(byte b[]
對於輸出流的flush
/**author by */
private void tempFileToTargetFile(ChildThread[] childThreads) {
try {
BufferedOutputStream outputStream = new BufferedOutputStream(
new FileOutputStream(fileDir + fileName));
// 遍歷所有子線程創建的臨時文件
for (int i =
if (statusError) {
for (int k =
if (childThreads[k]
childThreads[k]
}
System
break;
}
BufferedInputStream inputStream = new BufferedInputStream(
new FileInputStream(childThreads[i]
System
int len =
int count =
byte[] b = new byte[
while ((len = inputStream
count += len;
outputStream
if ((count %
outputStream
}
// b = new byte[
}
inputStream
// 刪除臨時文件
if (childThreads[i]
childThreads[i]
}
}
outputStream
outputStream
} catch (FileNotFoundException e) {
e
} catch (IOException e) {
e
}
}
//第一步
private long[] setThreadBreakpoint(String fileDir
long contentLength
File file = new File(fileDir + fileName);
long localFileSize = file
if (file
System
// 下載的目標文件已存在
if (localFileSize < contentLength) {
System
// 遍歷目標文件的所有臨時文件
File tempFileDir = new File(fileDir);
File[] files = tempFileDir
for (int k =
String tempFileName = files[k]
// 臨時文件的命名方式為
if (tempFileName != null && files[k]
&& tempFileName
int fileLongNum = Integer
tempFileName
// 為每個線程設置已下載的位置
startPos[fileLongNum] = files[k]
}
}
}
} else {
// 如果下載的目標文件不存在
try {
file
} catch (IOException e) {
e
}
}
return startPos;
}
public class DownloadStartup {
private static final String encoding =
public static void main(String[] args) {
DownloadTask downloadManager = new DownloadTask();
String urlStr =
downloadManager
downloadManager
}
}
From:http://tw.wingwit.com/Article/program/Java/hx/201311/26073.html