多线程下载
流 randomAccessFile
public class Demo_1 {
public static void main(String[] args) throws Exception {
//要下载的文件地址
String path = "http://10.40.155.230:8080/down/down.mp3";
//创建对象 调用下载文件方法 传入路径 和线程数
new Demo_1().download(path, 3);
}
private String getFileName(String path) {
//如果包含有"/"号 从最后一个"/"号 +1 的位置开始截取字符串
return path.substring(path.lastIndexOf("/")+1);
}
/*下载文件
* path 网络文件的路径
* threadSize 线程数
* */
private void download(String path,int threadSize) throws Exception {
//URL(String spec)
URL url = new URL(path);
//使用jdk自带的 HttpURLConnection向 URL发送 请求并输出响应结果
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
//请求方式 设置
connection.setRequestMethod("GET");
//连接超时 设置
connection.setConnectTimeout(5000);
/*http请求 状态码
* 200 成功 连上了服务器
* 4xx 客户端有问题
* 5xx 服务器端有问题
* */
if(connection.getResponseCode() == 200) {
//1 获取网络文件的长度
int length = connection.getContentLength();
//本地文件
File file = new File(getFileName(path));
//在本地生成一个长度与网络文件相同的文件
RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");
accessFile.setLength(length);//将获取到的网络文件的长度 当成本地文件的长度
accessFile.close();
//计算每条线程负责下载的数据量 10%3 每一条线程分配的数据量 宁多不少原则
int block = length % threadSize == 0 ? length/threadSize : length/threadSize + 1;
//循环创建3个线程
for(int threadId = 0;threadId < threadSize;threadId++) {
//线程号 每条线程负责的数量 地址 存储位置 启动线程
new DownloadThread(threadId,block,url,file).start();
}
}else {
System.out.println("连接失败");
}
}
private class DownloadThread extends Thread{
private int threadId; //线程号
private int block; //每条线程负责处理的数量
private URL url; //地址
private File file; //本地位置
public DownloadThread(int threadId,int block,URL url,File file) {
this.threadId = threadId;
this.block = block;
this.url = url;
this.file = file;
}
public void run() {
//计算线程从网络文件的什么位置开始下载
// 例如 文件长度 是 4 平均 每一块 2 threadId 0 block 2
//第一次 0 1 第二次 2 3 第三次 4 5
int start = threadId * block;
//计算下载到网络文件结束位置
int end = (threadId + 1) * block - 1;
try {
RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");
//每次从start位置开始 指针发生改变
accessFile.seek(start);
//使用jdk自带的 HttpURLConnection向 URL发送 请求并输出响应结果
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
//请求方式 设置
connection.setRequestMethod("GET");
//连接超时 设置
connection.setConnectTimeout(5000);
//Range
connection.setRequestProperty("Range", "bytes="+start+"-"+end);
//注意 多线程下载的状态码 是 206 不是 200
if(connection.getResponseCode() == 206) {
//流 将 要下载的内容 存入到自己的硬盘上
InputStream inputStream = connection.getInputStream();
byte[] buffer = new byte[1024];
int len = 0;
while((len = inputStream.read(buffer))!=-1) {
//将数据 写出到硬盘文件上
accessFile.write(buffer,0,len);
}
//关闭资源 释放流
accessFile.close();
inputStream.close();
}
System.out.println("第"+(threadId+1)+"条线程已经下载完成");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}