java 实现文件的断点续传(文件的分段上载)

java 实现文件的断点续传(文件的分段下载)

 

断点续传的原理:

把一个文件分为n个小文件,程序分n个线程去下载每一个小文件。阅读有关资料,IE浏览器传递给服务端的时候可以传递一个请求信息"Range":如:RANGE: bytes=2000070-  一看就知道告诉服务器下载的时候从2000070字节开始下载。值得注意的是response.getResponseCode()为206,不再是200了。

 

上代码:

 

/**
 * 下载工具类
 * 
 * @author aokunsang
 * 
 */
public class FileDownloader {

	private HttpURLConnection conn;

	public static void main(String[] args) throws Exception {
		FileDownloader load = new FileDownloader();
		load.download();
	}
	
	/**
	 * 开始下载
	 */
	public void download() throws Exception {
		HttpConnect connect = new HttpConnect(1);
		int fileSize = 0, threadSize = 3; // 文件长度和线程数
		conn = connect.initConnction();
		conn.connect();
		if (conn.getResponseCode() == 200) {
			fileSize = conn.getContentLength();
			conn.disconnect();
		}
		int perthThreadSize = fileSize / 3 + 1;   //每个线程需要下载的文件大小
		RandomAccessFile raf = new RandomAccessFile(new File("D://ca.mp3"), "rw");
		raf.setLength(fileSize);
		raf.close();
		long startTime = System.currentTimeMillis();
		for (int i = 0; i < threadSize; i++) {
			int startpos = i * perthThreadSize;  //线程开始下载的位置
			RandomAccessFile raff = new RandomAccessFile(new File("D://ca.mp3"), "rw");
			raff.seek(startpos);
			new myThread(startpos, perthThreadSize, i, raff).start();
		}
		long endTime = System.currentTimeMillis();
		
		while(Thread.activeCount()>1){}  //防止main线程结束而导致下载线程被销毁
		System.out.println("--------------下载完成,共耗时:"+(endTime-startTime)/(60*1000)+"分钟--------");
	}

	class myThread extends Thread {
		private int startpos;
		private int perThreadSize;
		private int threadId;
		private RandomAccessFile raf;

		public myThread(int startpos, int perThreadSize, int threadId,
				RandomAccessFile raf) {
			this.startpos = startpos;
			this.perThreadSize = perThreadSize;
			this.threadId = threadId;
			this.raf = raf;
		}

		@Override
		public void run() {
			HttpConnect connect = new HttpConnect(0);
			HttpURLConnection con = connect.initConnction();
			con.setRequestProperty("Range", "bytes=" + this.startpos + "-");
			try {
				InputStream is = con.getInputStream();
				byte[] bt = new byte[1024];
				int length = 0;
				int len = 0;
				while (length < this.perThreadSize && (len = is.read(bt)) != -1) {
					raf.write(bt, 0, len);
					length += len;
				}
				raf.close();
				is.close();
				System.out.println("线程"+threadId+"完成!");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	class HttpConnect {
		private int flag;

		public HttpConnect(int flag) {
			this.flag = flag;
		}

		public HttpURLConnection initConnction() {
			HttpURLConnection connection = null;
			try {
				URL url = new URL(HttpConnectParams.URLSTRING.content);
				connection = (HttpURLConnection) url.openConnection();
				connection.setConnectTimeout(Integer
						.parseInt(HttpConnectParams.CONNECTTIEMEDOUT.content));
				connection.setRequestMethod(HttpConnectParams.POST.content);
				connection.setRequestProperty(HttpConnectParams.ACCECT.header,
						HttpConnectParams.ACCECT.content);
				connection.setRequestProperty(
						HttpConnectParams.ACCECT_LANGAGE.header,
						HttpConnectParams.ACCECT_LANGAGE.content);
				connection.setRequestProperty(HttpConnectParams.CHARSET.header,
						HttpConnectParams.CHARSET.content);
				if (flag == 1) {
					connection.setRequestProperty(
							HttpConnectParams.KEEPCONNECT.header,
							HttpConnectParams.KEEPCONNECT.content);
				}
			} catch (Exception e) {
				connection = null;
			}
			return connection;
		}
	}
}

 

/**

 * HTTP请求的一些常量信息
 * @author aokunsang
 *
 */
public enum HttpConnectParams {
	/**
	 * URL地址(mp3格式的音乐文件)
	 */
	URLSTRING("http://www.61mp3.cn/music/%B6%F9%CD%AF%B8%E8%C7%FA/%CA%AE%B6%FE%C9%FA%D0%A4%B8%E8.mp3"),
	/**
	 * 请求的方式
	 */
	POST("GET"),
	/**
	 *  请求的格式
	 */
	ACCECT("Accept","image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*"),
	/**
	 * 请求的语言
	 */
	ACCECT_LANGAGE("Accept-Language","zh-CN"),
	/**
	 * 请求的字符集编码
	 */
	CHARSET("Charset","UTF-8"),
	/**
	 * 链接的超时数
	 */
	CONNECTTIEMEDOUT("5000"),
	/**
	 * 保持链接
	 */
	KEEPCONNECT("Connection","Keep-Alive");
	
	public String header; //标题
	public String content; //内容
	
	private HttpConnectParams(String header,String content) {
		this.header = header;
		this.content = content;
	}
	private HttpConnectParams(String content){
		this.content = content;
	}
}