基本原理:
利用URLConnection获取要下载文件的长度、头部等相关信息,并设置响应的头部信息。并且通过URLConnection获取输入流,将文件分成指定的块,每一块单独开辟一个线程完成数据的读取、写入。通过输入流读取下载文件的信息,然后将读取的信息用RandomAccessFile随机写入到本地文件中。(同时,每个线程写入的数据都文件指针也就是写入数据的长度,需要保存在一个临时文件中。这样当本次下载没有完成的时候,下次下载的时候就从这个文件中读取上一次下载的文件长度,然后继续接着上一次的位置开始下载。并且将本次下载的长度写入到这个文件中。)
/**
*内部实现
*/
public class Download extends Thread{
private int startIndex;//线程开始下载位置
private int endIndex;//线程结束下载位置
private int threadID;//线程编号
public Download(int startIndex, int endIndex, int threadID) {
this.startIndex = startIndex;
this.endIndex = endIndex;
this.threadID = threadID;
}
@Override
public void run() {
try {
//URL统一资源管理器,可以直接打开网络地址
URL url=new URL(DownloadTest.path);
//因为基于http请求,获取HttpURLConnection,获取网络链接对象,就可以和服务器建立链接
try {
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
//设置参数
conn.setRequestMethod("GET");//get请求
conn.setConnectTimeout(5000);//连接超时
conn.setReadTimeout(5000);//读取超时
conn.setRequestProperty("Range","bytes="+startIndex+"-"+endIndex);//设置范围请求参数,获取线程下载范围
if(conn.getResponseCode()==206){//表示部分数据ok
//取出连接中的数据
InputStream is=conn.getInputStream();//存储的是服务器上面 百度客户端数据
//提供一个接收数据的地方(本地接收)
File file=new File("BaiduNetdisk_6.9.7.4.exe");
//输出流,开始写数据,使用随机读写流
RandomAccessFile raf=new RandomAccessFile(file,"rwd");
raf.seek(startIndex);//跳转到每个线程,开始读取的位置
System.out.println("线程:"+threadID+" 开始的位置:"+startIndex+"---"+" 结束位置"+endIndex);
int len=0;
byte[] buf=new byte[1024];
while ((len=is.read(buf))!=-1){
raf.write(buf,0,len);
}
System.out.println("线程:"+threadID+"下载完毕...");
raf.close();
DownloadTest.finishedThread++;
//如果所有线程都下载完毕 ,让finishedThread 为0
synchronized (DownloadTest.path){
DownloadTest.finishedThread=0;
}
}
} catch (IOException e) {
e.printStackTrace();
}
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
/**
*多线程测试类
*/
public class DownloadTest {
static String path = "http://softforspeed.51xiazai.cn/down/BaiduNetdisk_6.9.7.4.exe";
static int threadCount = 3; //3个线程
static int finishedThread = 0; //和 线程数 有关 ,记录每一个线程是否执行完毕
public static void main(String[] args) throws IOException {
//统一资源管理器 ,可以直接打开 网络地址
URL url = new URL(DownloadTest.path);
//因为基于http请求 , 获取HttpURLConnection , 获取网络链接对象 ,就可以和服务器建立链接
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//设置一些参数
conn.setRequestMethod("GET"); //get请求
conn.setConnectTimeout(5000); //链接超时
conn.setReadTimeout(5000); //读取超时
if(conn.getResponseCode()==200){
//1.拿到文件总大小
int contentLength=conn.getContentLength();
//2.每个线程下载的大小
int size=contentLength/threadCount;
//3.开启线程执行下载
for (int i = 0; i <threadCount ; i++) {
int startIndex = i*size; // (i从0开始 )
int endIndex = (i+1)*size; //结束位置
Download thread = new Download(startIndex,endIndex,i);
thread.start();
}
}
}
}
执行结果:
线程:2 开始的位置:1067540--- 结束位置1601310
线程:1 开始的位置:533770--- 结束位置1067540
线程:0 开始的位置:0--- 结束位置533770
线程:0下载完毕...
线程:2下载完毕...
线程:1下载完毕...