Skip to content

Commit

Permalink
Merge pull request #48 from qilei/master
Browse files Browse the repository at this point in the history
完善多线程下载
  • Loading branch information
844028312 authored Mar 27, 2017
2 parents 3b3e38b + 3a4f316 commit 9259a57
Show file tree
Hide file tree
Showing 15 changed files with 454 additions and 11 deletions.
2 changes: 1 addition & 1 deletion group04/916758663/learn01/learn01.iml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="false">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_5" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,30 @@ public class ArrayList implements List {
private Object[] elementData = new Object[3];

public void add(Object o){
add(size,o);
ensureCapacity(size + 1);
elementData[size] = o;
size++;
}

public void add(int index, Object o){
if (index > size){
throw new IndexOutOfBoundsException();
}

// 扩容
if (size == elementData.length || index + 1 > elementData.length) {
int newLength = index + 1 > size * 2 ? index + 1 :size * 2;
elementData = Arrays.copyOf(elementData, newLength);
}
ensureCapacity(size + 1);

// 移动元素
System.arraycopy(elementData,index,elementData,index + 1 ,size-index);
elementData[index] = o;
size ++ ;
}


private void ensureCapacity(int minCapacity) {
int newLength = Math.max(minCapacity, size * 2);
elementData = Arrays.copyOf(elementData, newLength);
}

public Object get(int index){
checkIndex(index);
return elementData[index];
Expand Down Expand Up @@ -55,17 +62,17 @@ public Iterator iterator(){

private class ArrayListIterator implements Iterator {

private int currentIndex = 0;
private int position = 0;

@Override
public boolean hasNext() {
return currentIndex < size();
return position < size();
}

@Override
public Object next() {
Object o = get(currentIndex);
currentIndex ++ ;
Object o = get(position);
position++ ;
return o;
}
}
Expand Down
32 changes: 32 additions & 0 deletions group04/916758663/learn03/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.example</groupId>
<artifactId>download</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>

<name>download</name>
<url>http://maven.apache.org</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.6.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.example.download;


import com.example.download.api.Connection;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.concurrent.CountDownLatch;

public class DownloadThread extends Thread{

Connection conn;
int startPos;
int endPos;
String file;
CountDownLatch latch;

public DownloadThread( Connection conn, int startPos, int endPos,String file,CountDownLatch latch){

this.conn = conn;
this.startPos = startPos;
this.endPos = endPos;
this.file = file;
this.latch = latch;
}
public void run(){
RandomAccessFile randomAccessFile = null;
try {
byte[] data = conn.read(startPos, endPos);
randomAccessFile = new RandomAccessFile(file, "rw");
randomAccessFile.seek(startPos);
randomAccessFile.write(data);
latch.countDown();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (randomAccessFile != null) {
randomAccessFile.close();
}
} catch (IOException e) {
e.printStackTrace();
}
conn.close();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.example.download;


import com.example.download.api.Connection;
import com.example.download.api.ConnectionException;
import com.example.download.api.ConnectionManager;
import com.example.download.api.DownloadListener;
import java.util.concurrent.CountDownLatch;

public class FileDownloader {

String url;

String localFile;

DownloadListener listener;

ConnectionManager cm;

private CountDownLatch latch = new CountDownLatch(3);


public FileDownloader(String _url,String localFile) {
this.url = _url;
this.localFile = localFile;
}

public void execute(){
// 在这里实现你的代码, 注意: 需要用多线程实现下载
// 这个类依赖于其他几个接口, 你需要写这几个接口的实现代码
// (1) ConnectionManager , 可以打开一个连接,通过Connection可以读取其中的一段(用startPos, endPos来指定)
// (2) DownloadListener, 由于是多线程下载, 调用这个类的客户端不知道什么时候结束,所以你需要实现当所有
// 线程都执行完以后, 调用listener的notifiedFinished方法, 这样客户端就能收到通知。
// 具体的实现思路:
// 1. 需要调用ConnectionManager的open方法打开连接, 然后通过Connection.getContentLength方法获得文件的长度
// 2. 至少启动3个线程下载, 注意每个线程需要先调用ConnectionManager的open方法
// 然后调用read方法, read方法中有读取文件的开始位置和结束位置的参数, 返回值是byte[]数组
// 3. 把byte数组写入到文件中
// 4. 所有的线程都下载完成以后, 需要调用listener的notifiedFinished方法

// 下面的代码是示例代码, 也就是说只有一个线程, 你需要改造成多线程的。
Connection conn = null;
try {
conn = cm.open(this.url);
int length = conn.getContentLength();
int[][] array = Utils.split(length, 3);
for (int i = 0; i < 3; i++) {
new DownloadThread(conn,array[i][0],array[i][1],localFile,latch).start();
}

latch.await();

this.getListener().notifyFinished();

} catch (ConnectionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally{
}

}

public void setListener(DownloadListener listener) {
this.listener = listener;
}

public void setConnectionManager(ConnectionManager ucm){
this.cm = ucm;
}

public DownloadListener getListener(){
return this.listener;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.example.download;

/**
* Created by qilei on 17/3/26.
*/
public class Utils {

public static int[][] split(int len, int count) {
int[][] result = new int[count][2];
int baseLen = (int)Math.ceil(((double)len / count));
for (int i = 0; i < count; i++) {
int startPos = baseLen * i ;
int endPos = baseLen * (i + 1) -1;
if (i == count - 1) {
if (endPos > len - 1) {
endPos = len - 1;
}
}
result[i][0] = startPos;
result[i][1] = endPos;
}
return result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.example.download.api;

import java.io.IOException;

public interface Connection {
/**
* 给定开始和结束位置, 读取数据, 返回值是字节数组
* @param startPos 开始位置, 从0开始
* @param endPos 结束位置
* @return
*/
public byte[] read(int startPos, int endPos) throws IOException;
/**
* 得到数据内容的长度
* @return
*/
public int getContentLength();

/**
* 关闭连接
*/
public void close();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.example.download.api;

public class ConnectionException extends Exception {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.example.download.api;

public interface ConnectionManager {
/**
* 给定一个url , 打开一个连接
* @param url
* @return
*/
public Connection open(String url) throws ConnectionException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.example.download.api;

public interface DownloadListener {
public void notifyFinished();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.example.download.impl;

import com.example.download.api.Connection;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;


public class ConnectionImpl implements Connection {

private URL url;

ConnectionImpl(String urlStr){
try {
url = new URL(urlStr);
} catch (MalformedURLException e) {
e.printStackTrace();
}
}

@Override
public byte[] read(int startPos, int endPos) throws IOException {
URLConnection urlConnection = url.openConnection();
urlConnection.setRequestProperty("Range", "bytes=" + startPos + "-"
+ endPos);
InputStream inputStream = urlConnection.getInputStream();
int len = endPos + 1 - startPos;
int bytesRead = 0;
byte[] buffer = new byte[len];
while (bytesRead < len) {
int result = inputStream.read(buffer, bytesRead, len - bytesRead);
if (result == -1){
break;
}
bytesRead += result;
}
inputStream.close();
return buffer;
}

@Override
public int getContentLength() {
try {
URLConnection urlConnection = url.openConnection();
return urlConnection.getContentLength();
} catch (IOException e) {
e.printStackTrace();
}
return -1;
}

@Override
public void close() {
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.example.download.impl;


import com.example.download.api.Connection;
import com.example.download.api.ConnectionException;
import com.example.download.api.ConnectionManager;

public class ConnectionManagerImpl implements ConnectionManager {

@Override
public Connection open(String url) throws ConnectionException {
Connection conn = new ConnectionImpl(url);
return conn;
}

}
Loading

0 comments on commit 9259a57

Please sign in to comment.