packagecom.test.download;importjava.io.BufferedReader;importjava.io.File;importjava.io.FileInputStream;importjava.io.InputStream;importjava.io.InputStreamReader;importjava.io.RandomAccessFile;importjava.net.HttpURLConnection;importjava.net.URL;public classMutilDownLoad {//[1]定义下载的路径
private static String path = "http://192.168.33.10:80/test/123456.mp4";private static final int threadCount = 3; //假设开三个线程
private static int runningThread; //代表当前正在运行的线程
public static voidmain(String[] args) {//[一]获取服务器文件的大小 要计算每个线程下载的开始位置和结束位置
try{//(1) 创建一个url对象 参数就是网址
URL url = newURL(path);//(2)获取HttpURLConnection 链接对象
HttpURLConnection conn =(HttpURLConnection) url.openConnection();//(3)设置参数 发送get请求
conn.setRequestMethod("GET"); //默认请求 就是get 要大写//(4)设置链接网络的超时时间
conn.setConnectTimeout(5000);//(5)获取服务器返回的状态码
int code = conn.getResponseCode(); //200 代表获取服务器资源全部成功 206请求部分资源
if (code == 200) {//(6)获取服务器文件的大小
int length =conn.getContentLength();//[6.1]把 线程的数量赋值给正在运行的线程
runningThread =threadCount;
System.out.println("length:" +length);//[二] 创建一个大小和服务器一模一样的文件 目的提前把空间申请出来
RandomAccessFile rafAccessFile = new RandomAccessFile("F:\\"
+ getFilename(path), "rw");
rafAccessFile.setLength(length);//(7)算出每个线程下载的大小
int blockSize = length /threadCount;//[三 计算每个线程下载的开始位置和结束位置 ]
for (int i = 0; i < threadCount; i++) {int startIndex = i * blockSize; //每个线程下载的开始位置
int endIndex = (i + 1) * blockSize - 1;//特殊情况 就是最后一个线程
if (i == threadCount - 1) {//说明是最后一个线程
endIndex = length - 1;
}
System.out.println("线程id:::" + i + "理论下载的位置" + ":"
+ startIndex + "-----" +endIndex);//四 开启线程去服务器下载文件
DownLoadThread downLoadThread = newDownLoadThread(
startIndex, endIndex, i);
downLoadThread.start();
}
}
}catch(Exception e) {
e.printStackTrace();
}
}//定义线程去服务器下载文件
private static class DownLoadThread extendsThread {//通过构造方法把每个线程下载的开始位置和结束位置传递进来
private intstartIndex;private intendIndex;private intthreadId;public DownLoadThread(int startIndex, int endIndex, intthreadId) {this.startIndex =startIndex;this.endIndex =endIndex;this.threadId =threadId;
}
@Overridepublic voidrun() {//四 实现去服务器下载文件的逻辑
try{//(1) 创建一个url对象 参数就是网址
URL url = newURL(path);//(2)获取HttpURLConnection 链接对象
HttpURLConnection conn =(HttpURLConnection) url
.openConnection();//(3)设置参数 发送POST请求
conn.setRequestMethod("POST"); //默认请求 就是get 要大写//(4)设置链接网络的超时时间
conn.setConnectTimeout(5000);//[4.0]如果中间断过 继续上次的位置 继续下载 从文件中读取上次下载的位置
File file= new File("F:\\" + getFilename(path) +threadId+ ".txt");if (file.exists() && file.length() > 0) {
FileInputStream fis= newFileInputStream(file);
BufferedReader bufr= newBufferedReader(newInputStreamReader(fis));
String lastPositionn= bufr.readLine(); //读取出来的内容就是上一次下载的位置
int lastPosition =Integer.parseInt(lastPositionn);//[4.0.1]要改变一下 startIndex 位置
startIndex = lastPosition + 1;
System.out.println("线程id::" + threadId + "真实下载的位置" + ":"
+ startIndex + "-----" +endIndex);
fis.close();//关闭流
}//[4.1]设置一个请求头Range (作用告诉服务器每个线程下载的开始位置和结束位置)
conn.setRequestProperty("Range", "bytes=" + startIndex + "-"
+endIndex);//(5)获取服务器返回的状态码
int code = conn.getResponseCode(); //200 代表获取服务器资源全部成功//206请求部分资源 成功
if (code == 206) {//[6]创建随机读写文件对象
RandomAccessFile raf = new RandomAccessFile("F:\\"
+ getFilename(path), "rw");//[6]每个线程要从自己的位置开始写
raf.seek(startIndex);
InputStream in=conn.getInputStream();//[7]把数据写到文件中
int len = -1;byte[] buffer = new byte[1024 * 1024];//1Mb
int total = 0; //代表当前线程下载的大小
while ((len = in.read(buffer)) != -1) {
raf.write(buffer,0, len);
total+=len;//[8]实现断点续传 就是把当前线程下载的位置 给存起来 下次再下载的时候 就是按照上次下载的位置继续下载//就可以了
int currentThreadPosition = startIndex + total; //比如就存到一个普通的.txt文本中//[9]用来存当前线程下载的位置
RandomAccessFile raff = new RandomAccessFile("F:\\"
+ getFilename(path) + threadId + ".txt", "rwd");
raff.write(String.valueOf(currentThreadPosition)
.getBytes());
raff.close();
}
raf.close();//关闭流 释放资源
System.out.println("线程id:" + threadId + "---下载完毕了");//[10]把.txt文件删除 每个线程具体什么时候下载完毕了 我们不知道
synchronized (DownLoadThread.class) {
runningThread--;if (runningThread == 0) {//说明所有的线程都执行完毕了 就把.txt文件删除
for (int i = 0; i < threadCount; i++) {
File delteFile= new File("F:\\"
+ getFilename(path) + i + ".txt");
delteFile.delete();
}
}
}
}
}catch(Exception e) {
e.printStackTrace();
}
}
}//获取文件的名字
public staticString getFilename(String path) {int start = path.lastIndexOf("/") + 1;returnpath.substring(start);
}
}