首页 > 代码库 > 多线程下载文件的实现

多线程下载文件的实现

package cn.itcast.download;import java.io.IOException;import java.io.InputStream;import java.io.RandomAccessFile;import java.net.HttpURLConnection;import java.net.URL;public class testDownlaod {public static final String path="http://192.168.1.106:8080/youdao.exe";public static void main(String[]args) throws Exception{	URL url=new URL(path);	HttpURLConnection conn=(HttpURLConnection) url.openConnection();	conn.setRequestMethod("GET");	conn.setConnectTimeout(5000);	conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1)");	int code=conn.getResponseCode();	if(code==200){		int len=conn.getContentLength();		RandomAccessFile file=new RandomAccessFile("D://baiduyundownload/"+getFileName(path),"rwd");		//1.设置本地文件大小跟服务器的文件大小一致		file.setLength(len);		//2.假设开启3个线程		int threadnumber=3;		int blocksize=len/threadnumber;		/**		 * 线程的起始位置分别为		 * thread1 0~blocksize		 * thread2 1*blocksize~2*blocksize		 * thread3 2*blocksize~文件末尾		 */		for(int i=0;i<threadnumber;i++){			int startposition=i*blocksize;			int endposition=(i+1)*blocksize;			if(i==(threadnumber-1)){				//最后一个线程				endposition=len;			}						DownLoadTask task = new DownLoadTask(i,path,startposition,endposition);				task.start();		}			}		}public static String getFileName(String path) {	// TODO Auto-generated method stub	int start=path.lastIndexOf("/")+1;		return path.substring(start,path.length());}} class DownLoadTask extends Thread{		public static final String path="http://192.168.1.106:8080/youdao.exe";	int threadid;    String filepath;    int startposition;    int endposition;        public DownLoadTask(int threadid,String filepath,int startposition,int endposition){    	this.threadid=threadid;    	this.filepath=filepath;    	this.startposition=startposition;    	this.endposition=endposition;    	    }    @Override	public void run() {		// TODO Auto-generated method stub		try {			URL url=new URL(filepath);			HttpURLConnection conn=(HttpURLConnection) url.openConnection();			conn.setRequestProperty("Range", "bytes="+startposition+endposition);						conn.setRequestMethod("GET");			conn.setConnectTimeout(5000);			conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1)");			InputStream is=conn.getInputStream();			RandomAccessFile file=new RandomAccessFile(getFileName(path),"rwd");			//设置数据从文件哪个位置开始写			file.seek(startposition);			byte[]buffer=new byte[1024];			int len=0;			//rwd 代表当前读到的服务器数据的位置,同时这个值已经存储的文件位置			while((len=is.read(buffer))!=-1){				file.write(buffer,0,len);			}			file.close();			System.out.println("线程" + threadid + "下载完毕");		} catch (Exception e) {			// TODO Auto-generated catch block			e.printStackTrace();		}				super.run();			}    public static String getFileName(String path) {		int start = path.lastIndexOf("/") + 1;		return path.substring(start, path.length());	}}

基本原理:利用URLConnection获取要下载文件的长度、头部等相关信息,并设置响应的头部信息。并且通过URLConnection获取输入流,将文件分成指定的块,每一块单独开辟一个线程完成数据的读取、写入。通过输入流读取下载文件的信息,然后将读取的信息用RandomAccessFile随机写入到本地文件中。同时,每个线程写入的数据都文件指针也就是写入数据的长度,需要保存在一个临时文件中。这样当本次下载没有完成的时候,下次下载的时候就从这个文件中读取上一次下载的文件长度,然后继续接着上一次的位置开始下载。并且将本次下载的长度写入到这个文件中。

多线程下载文件的实现