Skip to content

Commit b8119e1

Browse files
committed
实现多线程下载器
1 parent d4c6bf6 commit b8119e1

File tree

9 files changed

+228
-47
lines changed

9 files changed

+228
-47
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
package org.wsc.coderising.download;
22

3+
import java.io.IOException;
4+
import java.io.RandomAccessFile;
5+
36
import org.wsc.coderising.download.api.Connection;
7+
import org.wsc.coderising.download.api.ConnectionException;
8+
import org.wsc.coderising.download.api.DownloadListener;
49

510
/**
6-
* 下载进程
11+
* 下载线程
712
*
813
* @author Administrator
914
* @date 2017年3月6日下午7:03:41
@@ -12,19 +17,45 @@
1217
*/
1318
public class DownloadThread extends Thread{
1419

20+
private RandomAccessFile accessFile;
1521
/** 连接 */
16-
Connection conn;
22+
private Connection conn;
1723
/** 开始处 */
18-
int startPos;
24+
private int startPos;
1925
/** 结束处 */
20-
int endPos;
21-
22-
public DownloadThread( Connection conn, int startPos, int endPos){
26+
private int endPos;
27+
/** 回调函数 */
28+
private DownloadListener listener;
29+
30+
public DownloadThread( Connection conn, int startPos, int endPos,DownloadListener listener){
2331
this.conn = conn;
2432
this.startPos = startPos;
2533
this.endPos = endPos;
34+
this.listener = listener;
2635
}
27-
public void run(){
36+
public void run(){
37+
try {
38+
byte[] bt = conn.read(startPos, endPos);
39+
accessFile = new RandomAccessFile("./"+conn.getFileName(), "rw");
40+
accessFile.seek(startPos);
41+
accessFile.write(bt);
42+
} catch (IOException e) {
43+
e.printStackTrace();
44+
} catch (ConnectionException e) {
45+
e.printStackTrace();
46+
}finally {
47+
if(accessFile != null){
48+
try {
49+
accessFile.close();
50+
} catch (IOException e) {
51+
e.printStackTrace();
52+
}
53+
}
54+
if (conn != null)
55+
conn.close();
56+
if(listener!=null)
57+
listener.notifyFinished();
58+
}
2859

2960
}
3061
}

group20/592146505/592146505Learning/src/org/wsc/coderising/download/FileDownloader.java

+25-17
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.wsc.coderising.download;
22

3+
import java.util.concurrent.atomic.AtomicInteger;
4+
35
import org.wsc.coderising.download.api.Connection;
46
import org.wsc.coderising.download.api.ConnectionException;
57
import org.wsc.coderising.download.api.ConnectionManager;
@@ -14,13 +16,15 @@
1416
*
1517
*/
1618
public class FileDownloader {
19+
private final static int THREAD_NUM = 10;
1720

18-
String url;
21+
private String url;
1922

20-
DownloadListener listener;
23+
private DownloadListener listener;
2124

22-
ConnectionManager cm;
25+
private ConnectionManager cm;
2326

27+
private AtomicInteger atomicInteger = new AtomicInteger();
2428

2529
public FileDownloader(String _url) {
2630
this.url = _url;
@@ -41,26 +45,30 @@ public void execute(){
4145
// 4. 所有的线程都下载完成以后, 需要调用listener的notifiedFinished方法
4246

4347
// 下面的代码是示例代码, 也就是说只有一个线程, 你需要改造成多线程的。
44-
Connection conn = null;
4548
try {
46-
47-
conn = cm.open(this.url);
48-
49-
int length = conn.getContentLength();
50-
51-
new DownloadThread(conn,0,length-1).start();
49+
int length = cm.getContentLength(url);
50+
int perThred_length = length/THREAD_NUM;
51+
int redundant = length%THREAD_NUM;
52+
for (int i = 0; i < THREAD_NUM; i++) {
53+
int startPos = i*perThred_length;
54+
int endPos = (i+1)*perThred_length-1;
55+
if(i == THREAD_NUM -1)//最后一个线程
56+
endPos+=redundant;
57+
Connection conn = cm.open(this.url);
58+
atomicInteger.getAndIncrement();
59+
new DownloadThread(conn,startPos,endPos,new DownloadListener() {
60+
@Override
61+
public void notifyFinished() {
62+
if(atomicInteger.decrementAndGet()==0)
63+
listener.notifyFinished();
64+
}
65+
}).start();
66+
}
5267

5368
} catch (ConnectionException e) {
5469
e.printStackTrace();
55-
}finally{
56-
if(conn != null){
57-
conn.close();
58-
}
5970
}
6071

61-
62-
63-
6472
}
6573

6674
public void setListener(DownloadListener listener) {

group20/592146505/592146505Learning/src/org/wsc/coderising/download/FileDownloaderTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public void tearDown() throws Exception {
2121
@Test
2222
public void testDownload() {
2323
// 资源位置
24-
String url = "http://localhost:8080/test.jpg";
24+
String url = "http://pic6.huitu.com/res/20130116/84481_20130116142820494200_1.jpg";
2525
// 创建资源下载器实例
2626
FileDownloader downloader = new FileDownloader(url);
2727
// 创建连接管理实例
@@ -47,7 +47,7 @@ public void notifyFinished() {
4747
e.printStackTrace();
4848
}
4949
}
50-
System.out.println("下载完成!");
50+
System.out.println("下载完成!请刷新项目根目录");
5151
}
5252

5353
}

group20/592146505/592146505Learning/src/org/wsc/coderising/download/api/Connection.java

+9-1
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,23 @@ public interface Connection {
1919
* @param endPos
2020
* 结束位置
2121
* @return
22+
* @throws IOException
23+
* @throws ConnectionException
2224
*/
23-
public byte[] read(int startPos, int endPos) throws IOException;
25+
public byte[] read(int startPos, int endPos) throws IOException, ConnectionException;
2426

2527
/**
2628
* 得到数据内容的长度
2729
*
2830
* @return
2931
*/
3032
public int getContentLength();
33+
34+
/**
35+
* 获取文件名称
36+
* @return
37+
*/
38+
public String getFileName();
3139

3240
/**
3341
* 关闭连接

group20/592146505/592146505Learning/src/org/wsc/coderising/download/api/ConnectionException.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,24 @@ public class ConnectionException extends Exception {
1313

1414
private static final long serialVersionUID = -249834831447340792L;
1515

16-
private ConnectionException() {
16+
public ConnectionException() {
1717
super();
1818
}
1919

20-
private ConnectionException(String message, Throwable cause, boolean enableSuppression,
20+
public ConnectionException(String message, Throwable cause, boolean enableSuppression,
2121
boolean writableStackTrace) {
2222
super(message, cause, enableSuppression, writableStackTrace);
2323
}
2424

25-
private ConnectionException(String message, Throwable cause) {
25+
public ConnectionException(String message, Throwable cause) {
2626
super(message, cause);
2727
}
2828

29-
private ConnectionException(String message) {
29+
public ConnectionException(String message) {
3030
super(message);
3131
}
3232

33-
private ConnectionException(Throwable cause) {
33+
public ConnectionException(Throwable cause) {
3434
super(cause);
3535
}
3636

group20/592146505/592146505Learning/src/org/wsc/coderising/download/api/ConnectionManager.java

+11-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
/**
44
*
5-
* 管理连接接口
5+
* 连接池接口
66
*
77
* @author Administrator
88
* @date 2017年3月6日下午7:02:30
@@ -15,6 +15,15 @@ public interface ConnectionManager {
1515
*
1616
* @param url
1717
* @return
18+
* @throws ConnectionException
1819
*/
19-
public Connection open(String url) throws ConnectionException;
20+
Connection open(String url) throws ConnectionException;
21+
22+
/**
23+
* 获取长度
24+
* @param urlStr
25+
* @return
26+
* @throws ConnectionException
27+
*/
28+
int getContentLength(String urlStr) throws ConnectionException;
2029
}
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
package org.wsc.coderising.download.impl;
22

3+
import java.io.BufferedInputStream;
4+
import java.io.ByteArrayOutputStream;
35
import java.io.IOException;
6+
import java.io.InputStream;
7+
import java.net.HttpURLConnection;
48

59
import org.wsc.coderising.download.api.Connection;
10+
import org.wsc.coderising.download.api.ConnectionException;
611

712
/**
813
*
@@ -14,22 +19,97 @@
1419
*
1520
*/
1621
public class ConnectionImpl implements Connection {
22+
23+
/** 默认缓冲大小 */
24+
private final static int DEFAULT_SIZE = 1024;
1725

18-
@Override
19-
public byte[] read(int startPos, int endPos) throws IOException {
26+
private HttpURLConnection conn;
27+
28+
private InputStream is;
29+
30+
private ByteArrayOutputStream bos;
2031

21-
return null;
32+
@SuppressWarnings("static-access")
33+
@Override
34+
public byte[] read(int startPos, int endPos) throws IOException, ConnectionException {
35+
// 设置读取范围
36+
conn.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos);
37+
conn.setFollowRedirects(true);//自动执行重定向
38+
conn.setConnectTimeout(30000);//等待响应时间
39+
checkStatus();
40+
byte[] buf = new byte[Math.min(getContentLength(), DEFAULT_SIZE)];
41+
is = new BufferedInputStream(conn.getInputStream());
42+
bos = new ByteArrayOutputStream();
43+
int lenth;//实际读取长度
44+
//读取
45+
while ((lenth = is.read(buf))!= -1)
46+
bos.write(buf, 0, lenth);
47+
return bos.toByteArray();
2248
}
2349

2450
@Override
2551
public int getContentLength() {
26-
27-
return 0;
52+
return conn.getContentLength();
2853
}
2954

3055
@Override
3156
public void close() {
57+
if (bos != null)
58+
try {
59+
bos.close();
60+
} catch (IOException e) {
61+
e.printStackTrace();
62+
}
63+
if (is != null)
64+
try {
65+
is.close();
66+
} catch (IOException e) {
67+
e.printStackTrace();
68+
}
69+
if(conn != null)
70+
conn.disconnect();
71+
}
72+
73+
@Override
74+
public String getFileName() {
75+
String fileName = null;
76+
String field = conn.getHeaderField("Content-Disposition");
77+
if(field == null ){
78+
String urlStr = conn.getURL().toString();
79+
fileName = urlStr.substring(urlStr.lastIndexOf("/")+1);
80+
}else{
81+
fileName=field.substring(field.indexOf("filename")+10, field.length()-1);
82+
}
83+
System.out.println(fileName);
84+
return fileName;
85+
}
86+
87+
/**
88+
* 检查连接状态
89+
* @throws ConnectionException
90+
*/
91+
private void checkStatus() throws ConnectionException {
92+
try {
93+
int responseCode = conn.getResponseCode();
94+
if (responseCode != HttpURLConnection.HTTP_OK && responseCode != HttpURLConnection.HTTP_PARTIAL) {
95+
throw new ConnectionException("server response code: " + responseCode);
96+
}
97+
} catch (IOException e) {
98+
throw new ConnectionException(e);
99+
}
100+
}
32101

102+
public HttpURLConnection getConn() {
103+
return conn;
33104
}
34105

106+
public void setConn(HttpURLConnection conn) {
107+
this.conn = conn;
108+
}
109+
110+
public ConnectionImpl(HttpURLConnection conn) {
111+
super();
112+
this.conn = conn;
113+
}
114+
35115
}

0 commit comments

Comments
 (0)