import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
public class Crazy_17_1 {
//下载资源的路径
private String path;
//所要下载资源的文件的保存位置
private String targetFile;
//下载所使用的线程数
private int threadNum;
//用于下载的线程对象
private DownThread[] threads;
//下载文件的大小
private int fileSize;
//初始化下载完成的线程个数
private int finishedThread = 0;
public Crazy_17_1(String path, String targetFile, int threadNum) {
this.path = path;
this.threadNum = threadNum;
//初始化threads数组
threads = new DownThread[threadNum];
this.targetFile = targetFile;
}
public void download() throws Exception{
URL url = new URL(path);
//HttpURLConnection是protected修饰的,无法直接new对象
//url的openConnection方法返回值是URLConnection类的对象,需要强转为HttpURLConnection
//所以直接通过url调用openConnection方法来实现创建HttpURLConnection的对象
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
// //设置请求方式
conn.setRequestMethod("GET");
fileSize = conn.getContentLength();
//是否需要加1?书上加了1,不加也可以
int currentPartSize = fileSize/threadNum ;
RandomAccessFile file = new RandomAccessFile(targetFile, "rw");
file.setLength(fileSize);
for(int i=0; i<threadNum; i++) {
//计算每个线程下载开始的位置
int startPos = i*currentPartSize;
int endPos = (i+1)*currentPartSize - 1;
//每个线程使用一个randomaccessfile进行下载
RandomAccessFile currentPart = new RandomAccessFile(targetFile, "rw");
//定位该线程的下载位置
currentPart.seek(startPos);
//创建下载线程
threads[i] = new DownThread(startPos, endPos, currentPartSize, currentPart, i);
threads[i].start();
}
}
public double getCompleteRate() {
int sumSize = 0;
for(int i=0; i<threadNum; i++) {
sumSize += threads[i].length;
}
return sumSize*1.0/fileSize;
}
public static void main(String[] args) throws Exception{
Crazy_17_1 downloadTest = new Crazy_17_1("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1524059184803&di=2ddb692113bbe27331b5ac91cad0ca05&imgtype=0&src=http%3A%2F%2Fimg762.ph.126.net%2FQd9w1tMvFTlICHT4NCWddg%3D%3D%2F4885842645743860383.png", "H:/Programing/download.png", 4);
downloadTest.download();
// new Thread(()->{
// while(downloadTest.getCompleteRate() < 1) {
// System.out.println("已完成: "+ downloadTest.getCompleteRate());
// try {
// Thread.sleep(10);
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
// }).start();
}
//用于下载的线程内部类
private class DownThread extends Thread{
// 当前线程的下载位置
private int startPos;
// 当前线程的下载结束位置
private int endPos;
// 定义当前线程负责下载的文件大小
private int currentPartSize;
// 当前线程需要下载的文件块
private RandomAccessFile currentPart;
// 定义已经该线程已下载的字节数
public int length;
//记录下载位置的指针
public int downloadPos;
//线程ID
public int ThreadID;
public DownThread(int startPos, int endPos, int currentPartSize,
RandomAccessFile currentPart,int ThreadID)
{
this.startPos = startPos;
this.endPos = endPos;
this.currentPartSize = currentPartSize;
this.currentPart = currentPart;
this.ThreadID = ThreadID;
}
public void run(){
try {
//建立一个临时文件
File fileProgress = new File(ThreadID+".txt");
//判断储存下载进度的文件是否存在
if(fileProgress.exists()) {
FileInputStream fis = new FileInputStream(fileProgress);
BufferedReader br = new BufferedReader(new InputStreamReader(fis));
//从下载进度的临时文件中读取上一次下载的总进度,然后和原来文本的开始位置相加,得到新的下载位置
startPos += Integer.parseInt(br.readLine());
fis.close();
}
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
//设置请求数据的区间
conn.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos);
//请求部分数据的响应码是206
if(conn.getResponseCode() == 206) {
//获取输入流
InputStream inStream = conn.getInputStream();
byte[] buffer = new byte[1024];
int len = 0;
int total = 0;
//临时文件的引用
File file = new File(targetFile);
RandomAccessFile raf = new RandomAccessFile(file, "rwd");
//更新文件的写入位置
raf.seek(startPos);
while((len = inStream.read(buffer)) != -1) {
raf.write(buffer,0,len);
total += len;
// length += len;
RandomAccessFile fileProgressraf = new RandomAccessFile(fileProgress,"rwd");
//每一次读取流里面的数据后,把当前线程下载的总进度写入临时文件中
fileProgressraf.write((total+"").getBytes());
fileProgressraf.close();
}
System.out.println("线程" + ThreadID + "下载过程结束===========================");
raf.close();
//线程下载完成后,清理临时文件
finishedThread++;
//线程安全
synchronized(path) {
if(finishedThread == threadNum) {
for(int i=0; i<threadNum; i++) {
File fileToDelete = new File(i+".txt");
fileToDelete.delete();
}
finishedThread = 0;
}
}
}
}catch(Exception e) {
e.printStackTrace();
}
}
}
}
仿FlashGet的断点续传、多线程下载
最新推荐文章于 2018-08-13 15:26:01 发布