您的位置:首页 > 编程语言 > Java开发

java多线程下载

2016-03-10 14:04 381 查看
package com.hlj.download;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
* java多线程下载
* 1 获得要下载的文件的大小
* 2 用RandomAccessFile生成一个同等大小的文件,相当于一个容器
* 3 计算每个线程下载的开始位置和结束位置
* 4 用conn.setRequestProperty("Range", "bytes=" + start + "-" + end);获得要下载文件的部分资源
* 5 通过RandomAccessFile 的 seek(start)方法设置该线程对该容器写的位置
* @author wizard
*
*/
public class ThreadLoad {

private String path = null;

private int threadNum = 1;

private boolean pause = false;

private String name = null;

private MyThread thread[];

private int contentLength = -1;

private AtomicInteger count = new AtomicInteger(0);// 判断是否全部线程执行完

public AtomicLong downProgress = new AtomicLong(0);// 判断是否全部线程执行完

public ThreadLoad(String path, String name, int threadNum) {
this.path = path;
this.name = name;
this.threadNum = threadNum;
thread = new MyThread[threadNum + 1];
}

public ThreadLoad(int threadNum) {
this.threadNum = threadNum;
thread = new MyThread[threadNum + 1];
}

public ThreadLoad() {
thread = new MyThread[threadNum + 1];
}

public String getPath() {
return path;
}

public void setPath(String path) {
this.path = path;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getThreadNum() {
return threadNum;
}

public boolean downLoadFile(String path, String name) throws IOException {
setPath(path);
setName(name);
return downLoadFile();
}

/**
* 判断是否全部结束额
* @return
*/
public boolean finish(){

return count.get() == threadNum;
}

/**
* 下载
*
* @return
* @throws IOException
*/
public boolean downLoadFile() throws IOException {

if ("".equals(path) || path == null ) {
return false;
}

int len = getContentLength();

if (len != -1) {

setFileSize(name, len);// 创建文件
int blockSize = len / threadNum;
long begin = System.currentTimeMillis();
for (int threadId = 1; threadId <= threadNum; threadId++) {
int start = (threadId - 1) * blockSize;
int endIndex = threadId * blockSize - 1;
if (threadId == threadNum) {// 最后一个线程下载的长度要稍微长一点
endIndex = len;
}
System.out.println("线程:" + threadId + "下载:---" + start + "--->" + endIndex);
thread[threadId] = new MyThread(threadId, start, endIndex, name);
thread[threadId].start();
}

} else {
return false;
}

return true;
}

/**
* 暂停下载
*/
public void pauseDown() {
pause = true;
}

/**
* 继续下载
*/
public void contiuneDown() {

pause = false;

for (int i = 1; i <= threadNum; i++) {
if (thread[i] != null) {
synchronized (thread[i]) {
thread[i].notify();
}
}
}

}

/**
* 先设置一个空的文件 但长度要和要下载的一样大 相当于一个容器
*
* @param name
* @param len
* @throws IOException
*/
public void setFileSize(String name, int len) throws IOException {
RandomAccessFile raf = new RandomAccessFile(name, "rw");
raf.setLength(len);
raf.close();
}

/**
* 得到文件的总长度
*
* @return
* @throws IOException
*/
public int getContentLength() {

try {
if (contentLength == -1) {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
int code = conn.getResponseCode();

if (code == 200) {
String urlPath = conn.getURL().getFile();
String fileFullName = urlPath.substring(urlPath.lastIndexOf("/") + 1);

if (name == null || "".equals(name)) {
name = fileFullName;
}

contentLength = conn.getContentLength();
}
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (ProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

return contentLength;
}

/**
* 下载的线程
*
* @author Administrator
*
*/
class MyThread extends Thread {

private int threadId;
private int start;
private int end;
private String name;

public MyThread(int threadId, int start, int end, String name) {
super();
this.threadId = threadId;
this.start = start;
this.end = end;
this.name = name;
}

@Override
public void run() {

try {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
// 重要:请求服务器下载部分文件 指定文件的位置
conn.setRequestProperty("Range", "bytes=" + start + "-" + end);
// 从服务器请求全部资源返回200 如果从服务器请求部分资源 返回 206
int code = conn.getResponseCode();

InputStream is = conn.getInputStream();// 已经设置了请求的位置,返回的是当前位置对应的文件的输入流
RandomAccessFile raf = new RandomAccessFile(name, "rwd");
raf.seek(start);

int len = 0;
byte[] buffer = new byte[1024];
while ((len = is.read(buffer)) != -1) {
if (pause) {
synchronized (this) {
wait();
}
}
raf.write(buffer, 0, len);
downProgress.addAndGet(len);
}
is.close();
raf.close();
System.out.println("线程:" + threadId + "下载完毕");
count.incrementAndGet();

} catch (MalformedURLException e) {
e.printStackTrace();
} catch (ProtocolException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}

}

}

}
测试
<pre name="code" class="java">public static void main(String[] args) throws IOException, InterruptedException {

ThreadLoad down = new ThreadLoad("http://localhost:8080/downLoad/down/qwe.mp4",null, 5);
down.downLoadFile();

long preLen = 0;
int len = down.getContentLength();

while (!down.finish()) {
Thread.sleep(1000);

long now = down.downProgress.get();
float speed = ((float)(now - preLen) / 1024);
if(speed==0.0){
speed=1f;
}
float precent = (((float) now) / len) * 100;
float total = (float)len/1024/1024;
float surplusTime = ((len-now)/speed)/1000;

System.out.println("已下载: " + now + "---" + precent + "%" + " 下载速度:"
+  speed + "k/"+total+"M 剩余"+surplusTime+"秒");
preLen = down.downProgress.get();
}
}



                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: