0
点赞
收藏
分享

微信扫一扫

使用Apache HttpClient实现多线程下载的小例子


网上类似的文章很多,参考了很多人的,大部分人都是用URLConnection写的。

原理一:HTTP多线程下载原理

1、发送一个含有Rang头的Head请求,如果返回状态码为206,则允许多线程下载

 

原理二:多线程下载原理

1、使用HttpClient的Head请求获取请求文件的信息

2、发送一个Rang的Head请求判断是否允许多线程下载

3、通过主任务创建多个分段下载线程,分段下载文件,然后用Java的随机读写文件类保存下载的内容

 

等有时间了再添加内容吧,先简单写这么多

调度功能代码片段

Java代码

/**
* 开始下载
* @throws Exception
*/
public void startDown() throws Exception{
HttpClient httpClient = new DefaultHttpClient();
try {
//获取下载文件信息
getDownloadFileInfo(httpClient);
//启动多个下载线程
startDownloadThread();
//开始监视下载数据
monitor();
} catch (Exception e) {
throw e;
} finally {
httpClient.getConnectionManager().shutdown();
}
}

/**
* 获取下载文件信息
*/
private void getDownloadFileInfo(HttpClient httpClient) throws IOException,
ClientProtocolException, Exception {
HttpHead httpHead = new HttpHead(url);
HttpResponse response = httpClient.execute(httpHead);
//获取HTTP状态码
int statusCode = response.getStatusLine().getStatusCode();

if(statusCode != 200) throw new Exception("资源不存在!");
if(getDebug()){
for(Header header : response.getAllHeaders()){
System.out.println(header.getName()+":"+header.getValue());
}
}

//Content-Length
Header[] headers = response.getHeaders("Content-Length");
if(headers.length > 0)
contentLength = Long.valueOf(headers[0].getValue());

httpHead.abort();

httpHead = new HttpHead(url);
httpHead.addHeader("Range", "bytes=0-"+(contentLength-1));
response = httpClient.execute(httpHead);
if(response.getStatusLine().getStatusCode() == 206){
acceptRanges = true;
}
httpHead.abort();
}

/**
* 启动多个下载线程
* @throws IOException
* @throws FileNotFoundException
*/
private void startDownloadThread() throws IOException,
FileNotFoundException {
//创建下载文件
File file = new File(localPath);
file.createNewFile();
RandomAccessFile raf = new RandomAccessFile(file, "rw");
raf.setLength(contentLength);
raf.close();

//定义下载线程事件实现类
DownloadThreadListener listener = new DownloadThreadListener() {
public void afterPerDown(DownloadThreadEvent event) {
//下载完一个片段后追加已下载字节数
synchronized (object) {
DownloadTask.this.receivedCount += event.getCount();
}
}

public void downCompleted(DownloadThreadEvent event) {
//下载线程执行完毕后从主任务中移除
threads.remove(event.getTarget());
if(getDebug()){
System.out.println("剩余线程数:"+threads.size());
}
}
};

//不支持多线程下载时
if (!acceptRanges) {
if(getDebug()){
System.out.println("该地址不支持多线程下载");
}
//定义普通下载
DownloadThread thread = new DownloadThread(url, 0, contentLength, file, false);
thread.addDownloadListener(listener);
thread.start();
threads.add(thread);
return;
}

//每个请求的大小
long perThreadLength = contentLength / threadCount + 1;
long startPosition = 0;
long endPosition = perThreadLength;
//循环创建多个下载线程
do{
if(endPosition >= contentLength)
endPosition = contentLength - 1;

DownloadThread thread = new DownloadThread(url, startPosition, endPosition, file);
thread.addDownloadListener(listener);
thread.start();
threads.add(thread);

startPosition = endPosition + 1;//此处加 1,从结束位置的下一个地方开始请求
endPosition += perThreadLength;
} while (startPosition < contentLength);
}

/**
* 开始下载
* @throws Exception
*/
public void startDown() throws Exception{
HttpClient httpClient = new DefaultHttpClient();
try {
//获取下载文件信息
getDownloadFileInfo(httpClient);
//启动多个下载线程
startDownloadThread();
//开始监视下载数据
monitor();
} catch (Exception e) {
throw e;
} finally {
httpClient.getConnectionManager().shutdown();
}
}

/**
* 获取下载文件信息
*/
private void getDownloadFileInfo(HttpClient httpClient) throws IOException,
ClientProtocolException, Exception {
HttpHead httpHead = new HttpHead(url);
HttpResponse response = httpClient.execute(httpHead);
//获取HTTP状态码
int statusCode = response.getStatusLine().getStatusCode();

if(statusCode != 200) throw new Exception("资源不存在!");
if(getDebug()){
for(Header header : response.getAllHeaders()){
System.out.println(header.getName()+":"+header.getValue());
}
}

//Content-Length
Header[] headers = response.getHeaders("Content-Length");
if(headers.length > 0)
contentLength = Long.valueOf(headers[0].getValue());

httpHead.abort();

httpHead = new HttpHead(url);
httpHead.addHeader("Range", "bytes=0-"+(contentLength-1));
response = httpClient.execute(httpHead);
if(response.getStatusLine().getStatusCode() == 206){
acceptRanges = true;
}
httpHead.abort();
}

/**
* 启动多个下载线程
* @throws IOException
* @throws FileNotFoundException
*/
private void startDownloadThread() throws IOException,
FileNotFoundException {
//创建下载文件
File file = new File(localPath);
file.createNewFile();
RandomAccessFile raf = new RandomAccessFile(file, "rw");
raf.setLength(contentLength);
raf.close();

//定义下载线程事件实现类
DownloadThreadListener listener = new DownloadThreadListener() {
public void afterPerDown(DownloadThreadEvent event) {
//下载完一个片段后追加已下载字节数
synchronized (object) {
DownloadTask.this.receivedCount += event.getCount();
}
}

public void downCompleted(DownloadThreadEvent event) {
//下载线程执行完毕后从主任务中移除
threads.remove(event.getTarget());
if(getDebug()){
System.out.println("剩余线程数:"+threads.size());
}
}
};

//不支持多线程下载时
if (!acceptRanges) {
if(getDebug()){
System.out.println("该地址不支持多线程下载");
}
//定义普通下载
DownloadThread thread = new DownloadThread(url, 0, contentLength, file, false);
thread.addDownloadListener(listener);
thread.start();
threads.add(thread);
return;
}

//每个请求的大小
long perThreadLength = contentLength / threadCount + 1;
long startPosition = 0;
long endPosition = perThreadLength;
//循环创建多个下载线程
do{
if(endPosition >= contentLength)
endPosition = contentLength - 1;

DownloadThread thread = new DownloadThread(url, startPosition, endPosition, file);
thread.addDownloadListener(listener);
thread.start();
threads.add(thread);

startPosition = endPosition + 1;//此处加 1,从结束位置的下一个地方开始请求
endPosition += perThreadLength;
} while (startPosition < contentLength);
}

1. /**
2. * 开始下载
3. * @throws Exception
4. */
5. public void startDown() throws
6. new
7. try
8. //获取下载文件信息
9. getDownloadFileInfo(httpClient);
10. //启动多个下载线程
11. startDownloadThread();
12. //开始监视下载数据
13. monitor();
14. catch
15. throw
16. finally
17. httpClient.getConnectionManager().shutdown();
18. }
19. }
20.
21. /**
22. * 获取下载文件信息
23. */
24. private void getDownloadFileInfo(HttpClient httpClient) throws
25. ClientProtocolException, Exception {
26. new
27. HttpResponse response = httpClient.execute(httpHead);
28. //获取HTTP状态码
29. int
30.
31. if(statusCode != 200) throw new Exception("资源不存在!");
32. if(getDebug()){
33. for(Header header : response.getAllHeaders()){
34. ":"+header.getValue());
35. }
36. }
37.
38. //Content-Length
39. "Content-Length");
40. if(headers.length > 0)
41. 0].getValue());
42.
43. httpHead.abort();
44.
45. new
46. "Range", "bytes=0-"+(contentLength-1));
47. response = httpClient.execute(httpHead);
48. if(response.getStatusLine().getStatusCode() == 206){
49. true;
50. }
51. httpHead.abort();
52. }
53.
54. /**
55. * 启动多个下载线程
56. * @throws IOException
57. * @throws FileNotFoundException
58. */
59. private void startDownloadThread() throws
60. FileNotFoundException {
61. //创建下载文件
62. new
63. file.createNewFile();
64. new RandomAccessFile(file, "rw");
65. raf.setLength(contentLength);
66. raf.close();
67.
68. //定义下载线程事件实现类
69. new
70. public void
71. //下载完一个片段后追加已下载字节数
72. synchronized
73. this.receivedCount += event.getCount();
74. }
75. }
76.
77. public void
78. //下载线程执行完毕后从主任务中移除
79. threads.remove(event.getTarget());
80. if(getDebug()){
81. "剩余线程数:"+threads.size());
82. }
83. }
84. };
85.
86. //不支持多线程下载时
87. if
88. if(getDebug()){
89. "该地址不支持多线程下载");
90. }
91. //定义普通下载
92. new DownloadThread(url, 0, contentLength, file, false);
93. thread.addDownloadListener(listener);
94. thread.start();
95. threads.add(thread);
96. return;
97. }
98.
99. //每个请求的大小
100. long perThreadLength = contentLength / threadCount + 1;
101. long startPosition = 0;
102. long
103. //循环创建多个下载线程
104. do{
105. if(endPosition >= contentLength)
106. 1;
107.
108. new
109. thread.addDownloadListener(listener);
110. thread.start();
111. threads.add(thread);
112.
113. 1;//此处加 1,从结束位置的下一个地方开始请求
114. endPosition += perThreadLength;
115. while
116. }

 分段下载线程代码片段:

Java代码 ​​​​ 

1. 
2. /**
3. * 现在过程代码
4. */
5. public void
6. if(DownloadTask.getDebug()){
7. "Start:" + startPosition + "-"
8. }
9. new
10. try
11. new
12. if(isRange){//多线程下载
13. "Range", "bytes="+startPosition+"-"+endPosition);
14. }
15. HttpResponse response = httpClient.execute(httpGet);
16. int
17. if(DownloadTask.getDebug()){
18. for(Header header : response.getAllHeaders()){
19. ":"+header.getValue());
20. }
21. "statusCode:"
22. }
23. if(statusCode == 206 || (statusCode == 200
24. InputStream inputStream = response.getEntity().getContent();
25. //创建随机读写类
26. new RandomAccessFile(file, "rw");
27. //跳到指定位置
28. outputStream.seek(startPosition);
29. int count = 0;byte[] buffer=new byte[1024];
30. while((count = inputStream.read(buffer, 0, buffer.length))>0){
31. 0, count);
32. //触发下载事件
33. new DownloadThreadEvent(this,count));
34. }
35. outputStream.close();
36. }
37. httpGet.abort();
38. catch
39. e.printStackTrace();
40. finally
41. //触发下载完成事件
42. new DownloadThreadEvent(this, endPosition));
43. if(DownloadTask.getDebug()){
44. "End:" + startPosition + "-"
45. }
46. httpClient.getConnectionManager().shutdown();
47. }
48. }
/**
* 现在过程代码
*/
public void run() {
if(DownloadTask.getDebug()){
System.out.println("Start:" + startPosition + "-" +endPosition);
}
HttpClient httpClient = new DefaultHttpClient();
try {
HttpGet httpGet = new HttpGet(url);
if(isRange){//多线程下载
httpGet.addHeader("Range", "bytes="+startPosition+"-"+endPosition);
}
HttpResponse response = httpClient.execute(httpGet);
int statusCode = response.getStatusLine().getStatusCode();
if(DownloadTask.getDebug()){
for(Header header : response.getAllHeaders()){
System.out.println(header.getName()+":"+header.getValue());
}
System.out.println("statusCode:" + statusCode);
}
if(statusCode == 206 || (statusCode == 200 && !isRange)){
InputStream inputStream = response.getEntity().getContent();
//创建随机读写类
RandomAccessFile outputStream = new RandomAccessFile(file, "rw");
//跳到指定位置
outputStream.seek(startPosition);
int count = 0;byte[] buffer=new byte[1024];
while((count = inputStream.read(buffer, 0, buffer.length))>0){
outputStream.write(buffer, 0, count);
//触发下载事件
fireAfterPerDown(new DownloadThreadEvent(this,count));
}
outputStream.close();
}
httpGet.abort();
} catch (Exception e) {
e.printStackTrace();
} finally {
//触发下载完成事件
fireDownCompleted(new DownloadThreadEvent(this, endPosition));
if(DownloadTask.getDebug()){
System.out.println("End:" + startPosition + "-" +endPosition);
}
httpClient.getConnectionManager().shutdown();
}
}

/**
* 现在过程代码
*/
public void run() {
if(DownloadTask.getDebug()){
System.out.println("Start:" + startPosition + "-" +endPosition);
}
HttpClient httpClient = new DefaultHttpClient();
try {
HttpGet httpGet = new HttpGet(url);
if(isRange){//多线程下载
httpGet.addHeader("Range", "bytes="+startPosition+"-"+endPosition);
}
HttpResponse response = httpClient.execute(httpGet);
int statusCode = response.getStatusLine().getStatusCode();
if(DownloadTask.getDebug()){
for(Header header : response.getAllHeaders()){
System.out.println(header.getName()+":"+header.getValue());
}
System.out.println("statusCode:" + statusCode);
}
if(statusCode == 206 || (statusCode == 200 && !isRange)){
InputStream inputStream = response.getEntity().getContent();
//创建随机读写类
RandomAccessFile outputStream = new RandomAccessFile(file, "rw");
//跳到指定位置
outputStream.seek(startPosition);
int count = 0;byte[] buffer=new byte[1024];
while((count = inputStream.read(buffer, 0, buffer.length))>0){
outputStream.write(buffer, 0, count);
//触发下载事件
fireAfterPerDown(new DownloadThreadEvent(this,count));
}
outputStream.close();
}
httpGet.abort();
} catch (Exception e) {
e.printStackTrace();
} finally {
//触发下载完成事件
fireDownCompleted(new DownloadThreadEvent(this, endPosition));
if(DownloadTask.getDebug()){
System.out.println("End:" + startPosition + "-" +endPosition);
}
httpClient.getConnectionManager().shutdown();
}
}

 附件说明:

1、Download.jar为编译好的可运行程序

2、Download.zip为Eclipse项目文件

3、运行截图

使用Apache HttpClient实现多线程下载的小例子_file


 

 

  • ​​Download.jar​​ (928.1 KB)
  • 下载次数: 44
  • ​​DownLoad.zip​​ (832.5 KB)
  • 下载次数: 70

 

举报

相关推荐

0 条评论