Skip to content

Commit 92d1e44

Browse files
authored
Merge pull request onlyliuxin#47 from 240094626/master
work0315-240094626
2 parents 82f411c + a9c2dd5 commit 92d1e44

15 files changed

+1007
-1
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package com.coderising.download;
2+
3+
import java.io.RandomAccessFile;
4+
import java.util.concurrent.CyclicBarrier;
5+
6+
import com.coderising.download.api.Connection;
7+
8+
public class DownloadThread extends Thread{
9+
10+
private Connection conn;
11+
private int startPos;
12+
private int endPos;
13+
private int threadId;
14+
private String localFile;
15+
private static final int BUFF_LENGTH = 1024 * 4;
16+
boolean isFinished = false;
17+
int currSize = 0;
18+
CyclicBarrier barrier;
19+
20+
public DownloadThread( Connection conn, int startPos, int endPos,int threadId,String localFile,CyclicBarrier barrier){
21+
22+
this.conn = conn;
23+
this.startPos = startPos;
24+
this.endPos = endPos;
25+
this.threadId = threadId;
26+
this.localFile = localFile;
27+
this.barrier = barrier;
28+
}
29+
public void run(){
30+
try {
31+
System.out.println("Thread"+threadId+" begin download bytes range:"+startPos+"-"+endPos);
32+
RandomAccessFile raf = new RandomAccessFile(localFile, "rw");
33+
int totalLen = endPos - startPos + 1;
34+
while(currSize < totalLen){
35+
int start = currSize + startPos;
36+
int end = start + BUFF_LENGTH-1;
37+
byte[] data = conn.read(start,(end>endPos?endPos:end));
38+
39+
raf.seek(start);
40+
raf.write(data);
41+
currSize += data.length;
42+
43+
44+
}
45+
raf.close();
46+
barrier.await(); //等待别的线程完成
47+
} catch (Exception e) {
48+
e.printStackTrace();
49+
}
50+
}
51+
}
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package com.coderising.download;
2+
3+
import java.io.IOException;
4+
import java.io.RandomAccessFile;
5+
import java.util.concurrent.CyclicBarrier;
6+
7+
import com.coderising.download.api.Connection;
8+
import com.coderising.download.api.ConnectionManager;
9+
import com.coderising.download.api.DownloadListener;
10+
11+
12+
public class FileDownloader {
13+
14+
private String url;
15+
16+
private DownloadListener listener;
17+
18+
private ConnectionManager cm;
19+
20+
private String localFile;
21+
22+
private int threadNum;
23+
24+
//一组开始下载位置
25+
private int[] startPos;
26+
//一组结束下载位置
27+
private int[] endPos;
28+
29+
30+
public FileDownloader(String _url,int threadNum,String localFile) {
31+
this.url = _url;
32+
this.threadNum = threadNum;
33+
this.localFile = localFile;
34+
startPos = new int[threadNum];
35+
endPos = new int[threadNum];
36+
37+
}
38+
39+
public void execute(){
40+
// 在这里实现你的代码, 注意: 需要用多线程实现下载
41+
// 这个类依赖于其他几个接口, 你需要写这几个接口的实现代码
42+
// (1) ConnectionManager , 可以打开一个连接,通过Connection可以读取其中的一段(用startPos, endPos来指定)
43+
// (2) DownloadListener, 由于是多线程下载, 调用这个类的客户端不知道什么时候结束,所以你需要实现当所有
44+
// 线程都执行完以后, 调用listener的notifiedFinished方法, 这样客户端就能收到通知。
45+
// 具体的实现思路:
46+
// 1. 需要调用ConnectionManager的open方法打开连接, 然后通过Connection.getContentLength方法获得文件的长度
47+
// 2. 至少启动3个线程下载, 注意每个线程需要先调用ConnectionManager的open方法
48+
// 然后调用read方法, read方法中有读取文件的开始位置和结束位置的参数, 返回值是byte[]数组
49+
// 3. 把byte数组写入到文件中
50+
// 4. 所有的线程都下载完成以后, 需要调用listener的notifiedFinished方法
51+
52+
// 下面的代码是示例代码, 也就是说只有一个线程, 你需要改造成多线程的。
53+
54+
CyclicBarrier barrier = new CyclicBarrier(threadNum, new Runnable() {
55+
@Override
56+
public void run() {
57+
listener.notifyFinished();
58+
}
59+
});
60+
61+
Connection conn = null;
62+
try {
63+
64+
conn = cm.open(this.url);
65+
66+
int length = conn.getContentLength();
67+
68+
if(length > 0){
69+
holderFile(localFile,length);
70+
71+
for(int i = 0 , len = length/threadNum; i < threadNum; i++){
72+
int size = i * len;
73+
startPos[i] = size;
74+
if(i == threadNum-1){
75+
endPos[i] = length - 1;
76+
}else{
77+
endPos[i] = size + len-1;
78+
}
79+
new DownloadThread(cm.open(url),
80+
startPos[i],
81+
endPos[i],
82+
i+1,
83+
localFile,
84+
barrier).start();
85+
}
86+
87+
}
88+
89+
90+
} catch (Exception e) {
91+
e.printStackTrace();
92+
}finally{
93+
if(conn != null){
94+
conn.close();
95+
}
96+
}
97+
98+
99+
100+
101+
}
102+
103+
private void holderFile(String localFile, int length) throws IOException {
104+
RandomAccessFile raf = new RandomAccessFile(localFile, "rw");
105+
for(int i = 0; i < length; i++){
106+
raf.write(0);
107+
}
108+
raf.close();
109+
}
110+
111+
public void setListener(DownloadListener listener) {
112+
this.listener = listener;
113+
}
114+
115+
116+
117+
public void setConnectionManager(ConnectionManager ucm){
118+
this.cm = ucm;
119+
}
120+
121+
public DownloadListener getListener(){
122+
return this.listener;
123+
}
124+
125+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package com.coderising.download;
2+
3+
import org.junit.After;
4+
import org.junit.Before;
5+
import org.junit.Test;
6+
7+
import com.coderising.download.api.ConnectionManager;
8+
import com.coderising.download.api.DownloadListener;
9+
import com.coderising.download.impl.ConnectionManagerImpl;
10+
11+
public class FileDownloaderTest {
12+
boolean downloadFinished = false;
13+
@Before
14+
public void setUp() throws Exception {
15+
}
16+
17+
@After
18+
public void tearDown() throws Exception {
19+
}
20+
21+
@Test
22+
public void testDownload() {
23+
24+
String url = "http://images2015.cnblogs.com/blog/610238/201604/610238-20160421154632101-286208268.png";
25+
String localFile = "E:\\Users\\2017coding\\temp\\pic.png";
26+
int threadNum = Runtime.getRuntime().availableProcessors();
27+
FileDownloader downloader = new FileDownloader(url,threadNum,localFile);
28+
29+
30+
ConnectionManager cm = new ConnectionManagerImpl();
31+
downloader.setConnectionManager(cm);
32+
33+
downloader.setListener(new DownloadListener() {
34+
@Override
35+
public void notifyFinished() {
36+
downloadFinished = true;
37+
}
38+
39+
});
40+
41+
42+
downloader.execute();
43+
44+
// 等待多线程下载程序执行完毕
45+
while (!downloadFinished) {
46+
try {
47+
System.out.println("还没有下载完成,休眠五秒");
48+
//休眠5秒
49+
Thread.sleep(5000);
50+
} catch (InterruptedException e) {
51+
e.printStackTrace();
52+
}
53+
}
54+
System.out.println("下载完成!");
55+
56+
57+
58+
}
59+
60+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.coderising.download.api;
2+
3+
import java.io.IOException;
4+
5+
public interface Connection {
6+
/**
7+
* 给定开始和结束位置, 读取数据, 返回值是字节数组
8+
* @param startPos 开始位置, 从0开始
9+
* @param endPos 结束位置
10+
* @return
11+
* @throws Exception
12+
*/
13+
public byte[] read(int startPos,int endPos) throws Exception;
14+
/**
15+
* 得到数据内容的长度
16+
* @return
17+
*/
18+
public int getContentLength();
19+
20+
/**
21+
* 关闭连接
22+
*/
23+
public void close();
24+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package com.coderising.download.api;
2+
3+
import java.io.PrintStream;
4+
import java.io.PrintWriter;
5+
import java.io.StringWriter;
6+
7+
public class ConnectionException extends Exception {
8+
9+
private static final long serialVersionUID = 5581807994119179835L;
10+
private String message;
11+
private Throwable t;
12+
private String stackTrace;
13+
14+
public Throwable getCause(){
15+
return this.t;
16+
}
17+
18+
public String toString(){
19+
return this.message;
20+
}
21+
22+
public void printStackTrace() {
23+
System.err.print(this.stackTrace);
24+
}
25+
26+
public void printStackTrace(PrintStream paramPrintStream) {
27+
printStackTrace(new PrintWriter(paramPrintStream));
28+
}
29+
30+
public void printStackTrace(PrintWriter paramPrintWriter) {
31+
paramPrintWriter.print(this.stackTrace);
32+
}
33+
34+
public ConnectionException(String paramString) {
35+
super(paramString);
36+
this.message = paramString;
37+
this.stackTrace = paramString;
38+
}
39+
40+
public ConnectionException(Throwable paramThrowable) {
41+
super(paramThrowable.getMessage());
42+
this.t = paramThrowable;
43+
StringWriter localStringWriter = new StringWriter();
44+
paramThrowable.printStackTrace(new PrintWriter(localStringWriter));
45+
this.stackTrace = localStringWriter.toString();
46+
}
47+
48+
public ConnectionException(String paramString, Throwable paramThrowable) {
49+
super(paramString + "; nested exception is "
50+
+ paramThrowable.getMessage());
51+
this.t = paramThrowable;
52+
this.message = paramString;
53+
StringWriter localStringWriter = new StringWriter();
54+
paramThrowable.printStackTrace(new PrintWriter(localStringWriter));
55+
this.stackTrace = localStringWriter.toString();
56+
}
57+
58+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.coderising.download.api;
2+
3+
public interface ConnectionManager {
4+
/**
5+
* 给定一个url , 打开一个连接
6+
* @param url
7+
* @return
8+
*/
9+
public Connection open(String url) throws ConnectionException;
10+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.coderising.download.api;
2+
3+
public interface DownloadListener {
4+
public void notifyFinished();
5+
}

0 commit comments

Comments
 (0)