多线程下载大文件(断点续传)

RandomAccessFile

提到多线程下载大文件或者时断点续传,我们就肯定要提到 RandomAccessFile这个类,为啥可以多线程来下载一个大文件呢?得益于它强大的seek方法

然后提到断点续传呢,我觉得可以聊一聊Connection 头字段相关的内容


Connection

这个字段只在http 1.1 协议中存在。它决定了客户端和服务器进行了一次会话后,服务器是否立即关闭网络连接。

Connect有两个值:

    close 当read完数据时,就立即返回 keep-alive read完数据后,还得被阻塞一段时间,直到超时时间

http请求头字段

    Host 用于指定访问的主机名和端口号 Accept 确定客户端可以接受的媒体类型 User-Agent 指定客户端用什么方式访问的服务器 Range 利用该字段头来实现断点续传功能 (Range: bytes=1000-2000 传输范围时 1000-2000 Range: bytes=1000- 传输1000字节之后的数据)

http响应头字段

    Accept-Ranges 服务器是否支持断点续传 Content-Range 指定返回的web资源的字节范围

利用RandomAccessFile 实现多线程下载文件

public class RandomAccessFileTest {
	
	private final static int DEFAULT_THREAD_SIZE = 5;

	/**
	 * 下载文件的方法(内部通过RandomAccessFile实现多线程下载文件)
	 * @param url 下载链接
	 * @param destLocation 目标下载地址
	 */
	public void download(String url, String destLocation) {
		
		File dest = new File(destLocation);
		int fileSize = computeFileSize(url);
		if(fileSize <=0) {
			throw new RuntimeException("读取文件失败");
		}
		int singleSize = fileSize / DEFAULT_THREAD_SIZE;
		
		for(int i=0; i<DEFAULT_THREAD_SIZE; i++) {
			int startIndex = i * singleSize;
			int endIndex = (i+1) * singleSize;
			if(i == DEFAULT_THREAD_SIZE-1) {
				endIndex = fileSize;
			}
			new DownloadThread(url, dest, startIndex, endIndex).start();
		}
	}
	
	/**
	 * 计算需要下载的文件大小
	 * @param url 下载链接
	 * @return 文件大小
	 */
	private int computeFileSize(String url) {
		try {
			URL address = new URL(url);
			HttpURLConnection connection = (HttpURLConnection) address.openConnection();
			if(connection.getResponseCode() == 200) {
				return connection.getContentLength();
			}
			connection.disconnect();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return 0;
	}
	
	
	class DownloadThread extends Thread{
		
		private String url;
		private File destFile;
		private int startIndex;
		private int endIndex;

		public DownloadThread(String url, File destFile, int startIndex, int endIndex) {
			super();
			this.url = url;
			this.destFile = destFile;
			this.startIndex = startIndex;
			this.endIndex = endIndex;
		}

		@Override
		public void run() {
			try {
				URL address = new URL(url);
				HttpURLConnection connection = (HttpURLConnection) address.openConnection();
				//设置请求参数
				connection.setRequestProperty("User-Agent", "NetFox");
				connection.setRequestProperty("RANGE", "bytes="+startIndex+"-"+endIndex);
				connection.connect();
				//写文件
				RandomAccessFile raFile = new RandomAccessFile(destFile, "rw");
				raFile.seek(startIndex);
				
				InputStream inputStream = connection.getInputStream();
				BufferedInputStream bis = new BufferedInputStream(inputStream);
				int len = 0;
                byte[] b = new byte[2048];
                while ((len = bis.read(b)) != -1) {
                	raFile.write(b,0,len);
                }
                bis.close();
                raFile.close();
                connection.disconnect();
			}catch (IOException e) {
				e.printStackTrace();
			}
			
		}
		
	}
}
经验分享 程序员 微信小程序 职场和发展