多线文件下载与断点下载原理

知识点:1.文件下载的流程

                2.运用线程实现多线程下载

                3.实现断点下载功能

 

package com.wfc.thread;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
public class MutileThreadDownload {
   /*
    * 线程的数量
    */
	private static int threadCount=3;
	/*
	 * 每个下载区块的大小
	 */
	private static long blocksize;
	/*
	 * 正在运行线程的数量
	 */
	private static int runningThreadCount;
	public static void main(String[] args) throws IOException{
		//服务器文件的路径
		String path="http://127.0.0.1:8080/Thread/temp.exe";
		URL url=new URL(path);
		//返回一个远程对象的连接
		HttpURLConnection conn=(HttpURLConnection)url.openConnection();
		conn.setRequestMethod("GET");//设置连接的方法
		conn.setConnectTimeout(5000);//设置超时时间
		int code=conn.getResponseCode();   //得到消息码
		if(code==200){
			//得到服务器端返回 content-length 头字段的值,就是文件大小
			long size=conn.getContentLength();
			System.out.println("服务器文件的大小:"+size);
			blocksize=size/threadCount;
			//1.首先在本地创建一个大小和服务器一模一样的空白文件
			File file=new File("temp.exe");
			//创建随机访问文件流,rw参数非常重要,可以看看RandomAccessFile文件。同步
			RandomAccessFile raf=new RandomAccessFile(file,"rw");
			raf.setLength(size);
			//2.开启若干个子线程分别取下载对应的资源
			runningThreadCount=threadCount;
			for(int i=1;i<=threadCount;i++){
				long startIndex=(i-1)*blocksize;
				long endIndex=i*blocksize-1;
				if(i==threadCount){
					endIndex=size-1;
				}
				System.out.println("开启线程:"+i+"  下载的位置:   "+startIndex+"---->"+endIndex);
				new DownloadThread(path, i, startIndex, endIndex).start();
			}
		}
		conn.disconnect();
	}
	private static class DownloadThread extends Thread{
		private int threadId;
		private long startIndex;
		private long endIndex;
		private String path;
		public DownloadThread(String path,int threadId, long startIndex, long endIndex
				) {
			super();
			this.threadId = threadId;
			this.startIndex = startIndex;
			this.endIndex = endIndex;
			this.path = path;
		}
		public void run(){
		try {
			//当前线程下载的总大小
			//实现了断点下载
			int total=0;
			File positionFile=new File(threadId+".txt");
			URL url=new URL(path);
			HttpURLConnection conn=(HttpURLConnection)url.openConnection();
			conn.setRequestMethod("GET");
			//接着从上一次的位置继续下载数据
			if(positionFile.exists()&&positionFile.length()>0){//判断是否有记录
				FileInputStream fis=new FileInputStream(positionFile);
				BufferedReader br=new BufferedReader(new InputStreamReader(fis));
				//获取当前线程上次下载的总大小是多少
				String lasttotalstr=br.readLine();
				int lastTotal=Integer.valueOf(lasttotalstr);
				System.out.println("上次线程"+threadId+"下载的总大小:"+lastTotal);
				startIndex+=lastTotal;
				total+=lastTotal;  //加上上次下载的总大小
				fis.close();
			}
			//设置一般的请求属性:(key,value)
			conn.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex);;
		    conn.setConnectTimeout(5000);
		    int code=conn.getResponseCode();
		    System.out.println("code="+code);
		    InputStream is=conn.getInputStream();
		    File file=new File("temp.exe");
		    //随机文件的访问对象,rw为读写权限
		    RandomAccessFile raf=new RandomAccessFile(file,"rw");
		    //指定文件开始写入的位置,实际上马上要将下载下来的txt文件写到temp.exe文件中
		    raf.seek(startIndex);;
		    System.out.println("第"+threadId+"个线程:写文件的开始位置:"+String.valueOf(startIndex));
		    int len=0;
		    byte[] buffer=new byte[512];
		    while((len=is.read(buffer))!=-1){
		    	RandomAccessFile rf=new RandomAccessFile(positionFile,"rwd");
		    	raf.write(buffer,0,len);
		    	total+=len;
		    	rf.write(String.valueOf(total).getBytes());
		    	rf.close();
		    }
		    is.close();
		    raf.close();
		} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}finally{
				//只有所有的线程都下载完毕后,才可以删除记录文件
				synchronized(MutileThreadDownload.class){
					System.out.println("线程"+threadId+"下载完毕了");
					runningThreadCount--;
					if(runningThreadCount<1){
						System.out.println("所有线程都工作完毕了。删除临时记录的文件");
						for(int i=1;i<=threadCount;i++){
							File f=new File(i+".txt");
							System.out.println(f.delete());
						}
					}
				}
			}
		}
	}
}


 

 运行结果如下:

服务器文件的大小:5871941
开启线程:1  下载的位置:   0---->1957312
开启线程:2  下载的位置:   1957313---->3914625
开启线程:3  下载的位置:   3914626---->5871940
code=206
第1个线程:写文件的开始位置:0
code=206
第3个线程:写文件的开始位置:3914626
code=206
第2个线程:写文件的开始位置:1957313
线程1下载完毕了
线程2下载完毕了
线程3下载完毕了
所有线程都工作完毕了。删除临时记录的文件
true
true
true

多线程下载原理图:

多线文件下载与断点下载原理_第1张图片

你可能感兴趣的:(多线文件下载,断点下载原理)