为了更快的下载资源,我们可以采用多线程的方式来实现文件的下载。
多线程文件下载的基本原理如下:使用HttpURLConnection获取与资源指定URL的链接,httpurlconnection对象通过getContentLength可以获取下载文件的长度,等到需要下载的文件的长度以后,在本地创建一个与下载文件长度相同的文件,然后通过RandomAccessFile对文件进行写入操作,那么如何加入多线程呢?思想是将文件分为几个部分,每一个线程完成每一个部分的下载和文件写入操作。通过RandomAccessFile可以实现文件的随机访问,因此每个线程都可以讲自己负责下载的内容写到文件中指定的位置,而不用担心文件中内容出现错位。
下面是线程类的代码
public class MulThreadDownLoad extends Thread {
private String path;
private File file;
private int tasksize;
private int threadid;
public MulThreadDownLoad(String path ,File file , int tasksize, int threadid){
this.path = path; //文件路径
this.file = file; //文件
this.tasksize = tasksize; //单个线程的下载量
this.threadid = threadid; //线程的id
}
@Override
public void run() {
try {
int startPoint = threadid * tasksize; //每条线程写入文件的起点
int endPoint = (threadid + 1 ) * tasksize -1 ; //每条线程写入文件的终点
RandomAccessFile accessFile = new RandomAccessFile(file,"rwd");
accessFile.seek(startPoint);
HttpURLConnection con = (HttpURLConnection) new URL(path).openConnection();
con.setConnectTimeout(500);
con.setRequestMethod("GET");
// con.setRequestProperty("Range", "bytes="+startPoint+"-"+endPoint); 如果设置了Range字段,那么响应码是206而不是200
if(con.getResponseCode() == 200){
InputStream ins = con.getInputStream();
ins.skip(startPoint); //跳过前面线程已经下载过的内容,
byte [] buffer = new byte [1024];
int length = 0;
while((length = ins.read(buffer)) != -1 ){ //将读取的字节写入文件中
accessFile.write(buffer);
}
accessFile.close();
ins.close();
}
System.out.print((threadid +1 )+"线程已经下载完成 :");
System.out.println("bytes = "+startPoint+"-"+endPoint);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
下面这个是测试类,在测试类中,指定了文件下载的路径,通过文件的路径,获取了文件名
public class MulThreadDownLoadTest {
private File file ;
public static void main(String args []) throws Exception{
String path = "http://localhost:8080/test/jj.jpg";
new MulThreadDownLoadTest().download(path,3);
}
/*
* @path 指定下载的目标路径
* @threaCount 指定需要多少个线程进行下载
*/
public void download(String path, int threadCount ) throws Exception{
URL url = new URL(path);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
con.setConnectTimeout(500);
if(con.getResponseCode() == 200){
int ContentLength = con.getContentLength();//获取响应的长度
String fileName = getFileName(path); //获取文件名
file = new File(fileName);
System.out.println("下载文件大小"+ContentLength);
RandomAccessFile accessFile = new RandomAccessFile(file,"rwd"); //rwd 表示对文件内容的每个更新都同步写入到底层存储设备。
accessFile.setLength(ContentLength);
accessFile.close();
//计算每个线程的下载长度为多少
int tasksize = (ContentLength%threadCount == 0 ? ContentLength/threadCount : ContentLength/threadCount+ 1);
for(int threadid = 0; threadid < threadCount ;threadid++ ){
new MulThreadDownLoad(path,file,tasksize,threadid).start();
}
}
}
public static String getFileName(String path){
return path.substring(path.lastIndexOf("/")+1);
}
}
文章参考
传智播客培训视频
http://www.cnblogs.com/tiantianbyconan/archive/2013/02/20/2919132.html