多线程文件下载
</pre><pre name="code" class="java">import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.CountDownLatch;
public class FileDownLoader {
private static final int READ_TIMEOUT = 5 * 60 * 1000;
private static final int THREAD_COUNT = 2;
public FileDownLoader(String path, String savePath) {
super();
this.path = path;
this.savePath = savePath;
}
private String path; // 网络资源URL
private String savePath; // 下载后保存文件名
public void download() throws Exception {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(READ_TIMEOUT);
System.out.println(conn.getResponseCode() == 200 ? "连接成功" : "连接失败");
int filesize = conn.getContentLength();//得到文件大小
System.out.println("filesize:" + filesize);
conn.disconnect();
int blocksize = filesize / THREAD_COUNT + 1;
RandomAccessFile file = new RandomAccessFile(savePath, "rw");
file.setLength(filesize);//设置本地文件的大小
file.close();
// 线程计数器 0:通行, >0:等待
CountDownLatch startSignal = new CountDownLatch(1); //所有线程开始信号,初始化值是1,默认等待
CountDownLatch doneSignal = new CountDownLatch(THREAD_COUNT); //所有线程完成信号,初始化值是线程数,默认等待
for (int threadId = 1; threadId <= THREAD_COUNT ; threadId++) {
int startpos = (threadId - 1) * blocksize;//计算每条线程的下载位置
int endpos = threadId * blocksize -1;
if (threadId == THREAD_COUNT) {
endpos = filesize;
}
System.out.println("Thread-" + threadId + " is downloading " + startpos + "->" + endpos);
RandomAccessFile perthreadfile = new RandomAccessFile(savePath, "rw");//
perthreadfile.seek(startpos);//从文件的什么位置开始写入数据
new DownladerThread(threadId, path, startpos, endpos, perthreadfile, startSignal, doneSignal).start();
}
// 通知所有线程开始,1-1=0,放行
startSignal.countDown();
// 等待所有线程结束,子线程中实行-1操作,完成一个减去一个,所有都完成了,就变成0了,不在等待,继续执行下一行代码
doneSignal.await();
System.out.println("文件下载完成!");
}
private class DownladerThread extends Thread {
private int startpos; //从文件的什么位置开始下载
private int endpos; //下载到什么位置结束
private String path;
private RandomAccessFile file;
private int threadid;
private CountDownLatch startSignal;
private CountDownLatch doneSignal;
public DownladerThread(int threadid, String path, int startpos, int endpos, RandomAccessFile perthreadfile,
CountDownLatch startSignal, CountDownLatch doneSignal) {
this.path = path;
this.startpos = startpos;
this.endpos = endpos;
this.file = perthreadfile;
this.threadid = threadid;
this.startSignal = startSignal;
this.doneSignal = doneSignal;
}
@Override
public void run() {
try {
// 等待开始信号,如果是0,放行
this.startSignal.await();
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setReadTimeout(READ_TIMEOUT);
conn.setRequestProperty("Range", "bytes=" + this.startpos + "-" + this.endpos);
System.out.println("线程-" + threadid + " " +
((conn.getResponseCode() == 200 || conn.getResponseCode() == 206) ? "连接成功" : "连接失败"));
InputStream inStream = conn.getInputStream();
byte[] buffer = new byte[1024];
int len = 0;
while((len = inStream.read(buffer))!=-1){
file.write(buffer, 0, len);
}
file.close();
inStream.close();
System.out.println("线程-" + threadid + " " + "完成下载");
// 每结束一条线程信号量减一
this.doneSignal.countDown();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws Exception {
String path = "http://nb.baidupcs.com/file/83b68781234bbf8e441dfb61c0e01c39?bkt=p2-nb-815&fid=908029305-250528-526955738348260&time=1417078240&sign=FDTAXERLB-DCb740ccc5511e5e8fedcff06b081203-7NOHgl9ITcD3RHfUNtw2UHjjHQc%3D&to=nbb&fm=Nin,B,U,nc&newver=1&newfm=1&flow_ver=3&sl=81723458&expires=8h&rt=sh&r=156158280&mlogid=3273469455&vuk=908029305&vbdid=328837051&fin=2014-11-11%20235118.jpg&fn=2014-11-11%20235118.jpg";
String savePath = "d:/tt.jpg";
new FileDownLoader(path, savePath).download();
}
}