多线程实现HTTP下载器(断点续传)_使用IO和线程知识

1.断点续传:

所谓的断点续传就是断点或者断网能够从该位置继续下载(使用IO)

每次下载文件时都在临时文件里写入已传位置,下载完成后删除临时文件

2.分片:

该功能不是很完善

把文件通过计算分成4片

然后使用多线程下载

3.判断线程池所有线程完成

见我上一篇博客(传送门):判断线程池所有线程完成

直接贴代码吧:

1.自定义线程类:

package 多线程下载器;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.DecimalFormat;

public class MyDownLoadingThread implements Runnable {
	//获得分隔符
	private static String HH = System.getProperty("line.separator");
	//防止断网断电后文件重新下载使用临时文件保存下载进度
	private static String lsFile = "taget/ls.txt";
	//下载范围
	private long[] rangeAtoB = null;
	//HTTP地址
	private String STRURL = null;
	//保存文件名
	private String morenName = null;
	//最大字节数组长度
	private static int MAX=1024000;
	@Override
	public void run() {
		// TODO Auto-generated method stub
		HttpURLConnection connection = null;
		
		try {
			URL url = new URL(STRURL);
			connection = (HttpURLConnection)url.openConnection();
			File file = new File(lsFile);
			if(file.exists()) {
				try(BufferedReader reader = new BufferedReader(new FileReader(file))){
					String line = null;
					while((line=reader.readLine())!=null) {
						if(line.charAt(0)==Thread.currentThread().getName().charAt(Thread.currentThread().getName().length()-1)) {
							rangeAtoB[0] = Long.valueOf(line.substring(line.indexOf(':')+1,line.indexOf('-')));
							rangeAtoB[1] = Long.valueOf(line.substring(line.indexOf('-')+1));
							break;
						}
					}
				}
			}
			connection.addRequestProperty("Range", "bytes="+rangeAtoB[0]+"-"+rangeAtoB[1]);
			connection.connect();
			
			if(connection.getResponseCode()/100!=2) {
				System.out.println("未连接成功!,退出");
				return;
			}else {
				System.out.println(Thread.currentThread().getName()+"连接成功!");
			}
			
			if(this.morenName==null) {
				this.morenName = STRURL.substring(STRURL.lastIndexOf('/')+1);
			}else {
				if(STRURL.indexOf('.')!=-1)
				this.morenName+=STRURL.substring(STRURL.lastIndexOf('.'));
			}
			DecimalFormat decimalFormat = new DecimalFormat("0.00");
			DecimalFormat format = new DecimalFormat("0.00%");
			int fileLength = connection.getContentLength();//文件长度
			System.out.printf("文件大小: %.2fMB\n",fileLength/1024.0/1024);
			long timeStart = System.currentTimeMillis();
			try(InputStream inputStream = connection.getInputStream();
				BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
				RandomAccessFile accessFilec = new RandomAccessFile(new File("taget/"+this.morenName), "rw");		
				){
				long sec =rangeAtoB[0];
				accessFilec.seek(sec);
				byte[] bs = null;
				int avg = 0;//计数循环了几次,来算平均下载速度
				double sum = 0;
				while(secrangeAtoB[1]) {
						bs = new byte[(int) (rangeAtoB[1]-sec)];
					}else {
						bs = new byte[MAX];
					}
					for (int i = 0; i < bs.length; i++) {
						bs[i] = (byte) bufferedInputStream.read();
					}
					accessFilec.seek(sec);
					accessFilec.write(bs);
					writeLs(sec, rangeAtoB[1]);
					long endTime = System.currentTimeMillis();
					System.out.println(
							Thread.currentThread().getName()+"已下载: "+format.format(((double)sec-rangeAtoB[0])/(rangeAtoB[1]-rangeAtoB[0]))
					 		+",下载速度: "+decimalFormat.format((bs.length/1024.0/1024.0/((endTime-startTime)/1000.0)))+"MB/s"
					 		);
					sec+=MAX;
					avg++;
					sum+=(bs.length/1024.0/1024.0/((endTime-startTime)/1000.0));
				}
				long timeEnd = System.currentTimeMillis();
				if((timeEnd-timeStart)/1000.0<60) {
					System.out.println(Thread.currentThread().getName()+" 已下载完成!您本次的平均下载速度是: "+decimalFormat.format(sum/avg)+"MB/s"+",耗时: "+(timeEnd-timeStart)/1000.0+"s");
				}
				else {
					System.out.println(Thread.currentThread().getName()+" 已下载完成!您本次的平均下载速度是: "+decimalFormat.format(sum/avg)+"MB/s"+",耗时: "+(timeEnd-timeStart)/1000.0/1000.0+"min");
				}
			} 
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	/**
	 * 	写临时文件
	 * @param 字节数组的起始位置
	 * @param 字节数组的结束位置
	 */
	public  synchronized void writeLs(long a,long b) {
		File file = new File(lsFile);
		if(file.exists()) {
			try(	BufferedReader reader = new BufferedReader(new FileReader(file));
						){
				String line = null;
				StringBuffer buffer = new StringBuffer();
				while((line=reader.readLine())!=null) {
					if(line.charAt(0)==Thread.currentThread().getName().charAt(Thread.currentThread().getName().length()-1)) {
						buffer.append(Thread.currentThread().getName().substring(Thread.currentThread().getName().lastIndexOf('-')+1)
								+":"
								+String.valueOf(a)
								+"-"
								+String.valueOf(b)
								+HH);
					}else {
						buffer.append(line+HH);
					}
				}
//				System.out.println(buffer.toString());
				BufferedWriter writer = new BufferedWriter(new FileWriter(lsFile,false));
				writer.write(buffer.toString());
				writer.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}else {
			//该文件不存在时初始化
			try(BufferedWriter writer = new BufferedWriter(new FileWriter(lsFile,false))){
				writer.write(
						"1:0-0"+HH
						+"2:0-0"+HH
						+"3:0-0"+HH
						+"4:0-0"
						);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	
	
	public MyDownLoadingThread() {
		
	}
	
	public MyDownLoadingThread(String URL,long[] rangeAtoB) {
		this.STRURL = URL;
		this.rangeAtoB = rangeAtoB;
	}
	
	public MyDownLoadingThread(String URL,String morenName,long[] rangeAtoB) {
		this.STRURL = URL;
		this.morenName = morenName;
		this.rangeAtoB = rangeAtoB;
	}

}

2.服务类

package 多线程下载器;

import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class InitDemo {
	private static String lsFile = "taget/ls.txt";
	//下载
	public void downLoaing(String STRURL) {
		try {
			ExecutorService service = Executors.newCachedThreadPool();
			URL url = new URL(STRURL);
			HttpURLConnection connection = (HttpURLConnection) url.openConnection();
			long fileLength = connection.getContentLength();
			Thread threadA = null;
			Thread threadB = null;
			Thread threadC = null;
			Thread threadD = null;
			
			long FileDuan = fileLength/4;
			threadA = new Thread(new MyDownLoadingThread(STRURL, new long[] {0,FileDuan}), "A");
			threadB = new Thread(new MyDownLoadingThread(STRURL, new long[] {FileDuan+1,FileDuan*2}), "B");
			threadC = new Thread(new MyDownLoadingThread(STRURL, new long[] {FileDuan*2+1,FileDuan*3}), "C");
			threadD = new Thread(new MyDownLoadingThread(STRURL, new long[] {FileDuan*3+1,fileLength}), "D");
			
			service.submit(threadA);
			service.submit(threadB);
			service.submit(threadC);
			service.submit(threadD);
			
			service.shutdown();
			while(true) {
				if(service.isTerminated()) {
					System.out.println("下载完成!");
					//下载完成删除产生的临时文件
					new File(lsFile).delete();
					break;
				}else {
					Thread.sleep(200);
				}
			}
//			threadA.start();
//			threadB.start();
//			threadC.start();
//			threadD.start();	
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
	}
	
}

3.测试类:

package 多线程下载器;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Scanner;

public class TextDemo {
	//private static String STRURL = "http://pic.ibaotu.com/00/63/22/31Q888piC7wM.mp4";
	
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		InitDemo initDemo = new InitDemo();
		System.out.println("---HTTP下载器,输入END结束---");
		while(true) {
			System.out.print("请输入你要下载的HTTP地址: ");
			String str = in.next();
			if(str.equals("END")) {
				System.exit(0);
			}
			initDemo.downLoaing(str);
		}
	}
}	

运行效果:

多线程实现HTTP下载器(断点续传)_使用IO和线程知识_第1张图片

多线程实现HTTP下载器(断点续传)_使用IO和线程知识_第2张图片

束语:

由于没有学习过图形界面所以就把核心代码写上了然后做的比较粗糙233333,当然这不是最优代码,因为每次写入临时文件比较耗时资源

如果更好的思路,留言一下吧=-=,毕竟新手上路

你可能感兴趣的:(JavaSE)