Skip to content

Commit 691064c

Browse files
authored
Merge pull request #52 from chhsalex/master
upload homework for 3-12 (code)
2 parents 0022878 + 347ef9d commit 691064c

File tree

13 files changed

+919
-0
lines changed

13 files changed

+919
-0
lines changed
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package com.coderising.download;
2+
3+
import java.io.FileNotFoundException;
4+
import java.io.IOException;
5+
import java.io.RandomAccessFile;
6+
7+
import com.coderising.download.api.Connection;
8+
9+
public class DownloadThread extends Thread{
10+
11+
private static final String FILENAME = "test.jpg";
12+
13+
Connection conn;
14+
int startPos;
15+
int endPos;
16+
17+
DownloadThreadListener listener;
18+
int tag = 0;
19+
20+
public DownloadThread( Connection conn, int startPos, int endPos){
21+
22+
this.conn = conn;
23+
this.startPos = startPos;
24+
this.endPos = endPos;
25+
}
26+
27+
public void setTagAndListener(int tag, DownloadThreadListener listener) {
28+
this.tag = tag;
29+
this.listener = listener;
30+
}
31+
32+
public void run(){
33+
RandomAccessFile raf = null;
34+
int offset = startPos, len;
35+
byte[] buffer;
36+
try {
37+
raf = new RandomAccessFile(FILENAME, "rw");
38+
if (raf.length() == 0) {
39+
raf.setLength(conn.getContentLength());
40+
}
41+
raf.seek(startPos);
42+
do {
43+
len = endPos + 1 - offset;
44+
if (len > 10000) {
45+
len = 10000;
46+
}
47+
buffer = conn.read(offset, offset + len - 1);
48+
if (buffer == null) {
49+
processException(new NullPointerException());
50+
return;
51+
}
52+
raf.write(buffer);
53+
offset += len;
54+
} while (offset < endPos);
55+
if (listener != null) {
56+
listener.onFinished(conn, tag, true);
57+
}
58+
} catch (FileNotFoundException e) {
59+
processException(e);
60+
} catch (IOException e) {
61+
processException(e);
62+
} finally {
63+
if (raf != null) {
64+
try {
65+
raf.close();
66+
} catch (IOException e) {
67+
e.printStackTrace();
68+
}
69+
}
70+
}
71+
}
72+
73+
private void processException(Exception e) {
74+
e.printStackTrace();
75+
if (listener != null) {
76+
listener.onFinished(conn, tag, false);
77+
}
78+
}
79+
80+
public static interface DownloadThreadListener {
81+
public void onFinished(Connection conn, int tag, boolean succeeded);
82+
}
83+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package com.coderising.download;
2+
3+
import com.coderising.download.api.Connection;
4+
import com.coderising.download.api.ConnectionException;
5+
import com.coderising.download.api.ConnectionManager;
6+
import com.coderising.download.api.DownloadListener;
7+
import com.coding.basic.Stack;
8+
9+
10+
public class FileDownloader {
11+
12+
String url;
13+
14+
DownloadListener listener;
15+
16+
ConnectionManager cm;
17+
18+
// Use stack to check if all threads are finished
19+
// When a thread is started, an empty Object will be pushed in this stack;
20+
// when a thread is finished, an Object will be popped out.
21+
private Stack mStack;
22+
23+
public FileDownloader(String _url) {
24+
this.url = _url;
25+
26+
}
27+
28+
public void execute(){
29+
// 在这里实现你的代码, 注意: 需要用多线程实现下载
30+
// 这个类依赖于其他几个接口, 你需要写这几个接口的实现代码
31+
// (1) ConnectionManager , 可以打开一个连接,通过Connection可以读取其中的一段(用startPos, endPos来指定)
32+
// (2) DownloadListener, 由于是多线程下载, 调用这个类的客户端不知道什么时候结束,所以你需要实现当所有
33+
// 线程都执行完以后, 调用listener的notifiedFinished方法, 这样客户端就能收到通知。
34+
// 具体的实现思路:
35+
// 1. 需要调用ConnectionManager的open方法打开连接, 然后通过Connection.getContentLength方法获得文件的长度
36+
// 2. 至少启动3个线程下载, 注意每个线程需要先调用ConnectionManager的open方法
37+
// 然后调用read方法, read方法中有读取文件的开始位置和结束位置的参数, 返回值是byte[]数组
38+
// 3. 把byte数组写入到文件中
39+
// 4. 所有的线程都下载完成以后, 需要调用listener的notifiedFinished方法
40+
41+
Connection conn = null;
42+
try {
43+
int length = 0;
44+
45+
int threadNum = 3;
46+
mStack = new Stack();
47+
48+
DownloadThread.DownloadThreadListener dtListener = new DownloadThread.DownloadThreadListener() {
49+
50+
@Override
51+
public void onFinished(Connection conn, int tag, boolean succeeded) {
52+
System.out.println("Thread with tag " + tag + (succeeded?" succeeded":" failed") + " to download");
53+
mStack.pop();
54+
if (conn != null) {
55+
conn.close();
56+
}
57+
if (mStack.isEmpty()) {
58+
listener.notifyFinished();
59+
}
60+
}
61+
};
62+
63+
for (int i = 0; i < threadNum; i++) {
64+
conn = cm.open(this.url);
65+
if (length == 0) {
66+
length = conn.getContentLength();
67+
}
68+
mStack.push(new Object());
69+
DownloadThread dt = new DownloadThread(conn,length*i/threadNum,length*(i+1)/threadNum - 1);
70+
dt.setTagAndListener(i, dtListener);
71+
dt.start();
72+
System.out.println("DownloadThread with tag " + i + " created and started");
73+
}
74+
75+
} catch (ConnectionException e) {
76+
e.printStackTrace();
77+
} finally{
78+
// if(conn != null){
79+
// conn.close();
80+
// }
81+
}
82+
83+
}
84+
85+
public void setListener(DownloadListener listener) {
86+
this.listener = listener;
87+
}
88+
89+
90+
91+
public void setConnectionManager(ConnectionManager ucm){
92+
this.cm = ucm;
93+
}
94+
95+
public DownloadListener getListener(){
96+
return this.listener;
97+
}
98+
99+
}
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://localhost:8080/test.jpg";
25+
String url = "https://edmullen.net/test/rc.jpg";
26+
27+
FileDownloader downloader = new FileDownloader(url);
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: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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+
*/
12+
public byte[] read(int startPos,int endPos) throws IOException;
13+
/**
14+
* 得到数据内容的长度
15+
* @return
16+
*/
17+
public int getContentLength();
18+
19+
/**
20+
* 关闭连接
21+
*/
22+
public void close();
23+
}
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 class ConnectionException extends Exception {
4+
5+
}
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+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package com.coderising.download.impl;
2+
3+
import java.io.IOException;
4+
import java.io.InputStream;
5+
import java.net.URL;
6+
import java.net.URLConnection;
7+
8+
import com.coderising.download.api.Connection;
9+
import com.coderising.download.api.ConnectionException;
10+
11+
public class ConnectionImpl implements Connection{
12+
13+
private URLConnection mUrlConnection = null;
14+
private InputStream iStream;
15+
private int currPos = 0;
16+
17+
public ConnectionImpl(URL url) throws ConnectionException{
18+
try {
19+
mUrlConnection = url.openConnection();
20+
mUrlConnection.connect();
21+
iStream = mUrlConnection.getInputStream();
22+
} catch (IOException e) {
23+
mUrlConnection = null;
24+
e.printStackTrace();
25+
throw new ConnectionException();
26+
}
27+
}
28+
29+
@Override
30+
public byte[] read(int startPos, int endPos) throws IOException {
31+
32+
int bytesLen = endPos - startPos + 1;
33+
byte[] buffer = new byte[bytesLen];
34+
35+
if (currPos < startPos) {
36+
iStream.skip(startPos - currPos);
37+
} else if (currPos > startPos) {
38+
// should not read previous bytes of input stream.
39+
// return null to end this thread.
40+
return null;
41+
}
42+
43+
for (int offset = 0, len;
44+
bytesLen > 0 && (len = iStream.read(buffer, offset, bytesLen)) >= 0;
45+
offset += len, bytesLen -= len) ;
46+
currPos = endPos + 1;
47+
48+
return buffer;
49+
}
50+
51+
@Override
52+
public int getContentLength() {
53+
if (mUrlConnection != null) {
54+
return mUrlConnection.getContentLength();
55+
}
56+
return 0;
57+
}
58+
59+
@Override
60+
public void close() {
61+
try {
62+
if (iStream != null) {
63+
iStream.close();
64+
}
65+
} catch (IOException e) {
66+
e.printStackTrace();
67+
}
68+
currPos = 0;
69+
mUrlConnection = null;
70+
}
71+
72+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.coderising.download.impl;
2+
3+
import java.net.MalformedURLException;
4+
import java.net.URL;
5+
6+
import com.coderising.download.api.Connection;
7+
import com.coderising.download.api.ConnectionException;
8+
import com.coderising.download.api.ConnectionManager;
9+
10+
public class ConnectionManagerImpl implements ConnectionManager {
11+
12+
@Override
13+
public Connection open(String url) throws ConnectionException {
14+
15+
try {
16+
return new ConnectionImpl(new URL(url));
17+
} catch (MalformedURLException e) {
18+
e.printStackTrace();
19+
throw new ConnectionException();
20+
}
21+
}
22+
23+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.coding.basic;
2+
3+
public interface Iterator {
4+
public boolean hasNext();
5+
public Object next();
6+
public void remove();
7+
}

0 commit comments

Comments
 (0)