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资源的字节范围
1 |
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(); } } } } |