Java断点续传多线程下载器(2)- HttpURLConnection和IO流传输

743 阅读3分钟
  • 上回,咱把整个下载器的流程和原理给梳理一遍,很显然这里有几个重点知识点:如何和网络地址取得连接,也就是连接servlet以及IO流传输线程池(想用线程池,多线程的三种创建只用过前两种)。

HttpURLConnection开始

HttpURLConnection是Java提供的一个发起HTTP请求的基础类库,可以做到发起POST GET请求,我们这次只是需要获取和设置请求头来得到一些必要的文件信息等一些别的操作,相对来说比较简单。

HttpURLConnection的封装比较简略,很多事情需要我们自己干,不过我们本次涉及到的操作不多,没啥所谓,基础的东西用就是了。

统计下涉及到的API

  • 设置请求头:setRequestProperty

  • 获取请求头:getHeaderField

  • 连接超时: setConnectTimeout

  • 获取状态码:getResponseCode

用法和基本流程

  1. 第一步当然是建立连接

    URL url1 = new URL(url);//拿到一个URL对象
    HttpURLConnection httpURLConnection = (HttpURLConnection) url1.openConnection();
    //利用HttpURLConnection对象从网络中获取网页数据
    
  2. 为了避免连接超时,设置一下连接超时的限制(HttpURLConnection是基于HTTP协议的,其底层通过socket通信实现。如果不设置超时(timeout),在网络异常的情况下,可能会导致程序僵死而不继续往下执行。)

    httpURLConnection.setConnectTimeout(6*1000);//为了避免连接超时
    
  3. 正如我们之前所说的,我们可以对Content-Range字段进行设置,Content-Range:A-B 就是从第A个bytes开始下载到第B个bytes

    if (...){
            httpURLConnection.setRequestProperty("RANGE","bytes=" + start + "-" + end);
    	} else {
        	httpURLConnection.setRequestProperty("RANGE","bytes" + start + "-");
        }
    
  4. 当然还有获取大小

    int length = httpURLConnection.getContentLength();
    
  5. 获取请求头来得到 Etag

    Map<String, List<String>> headerFields = httpUrlConnection.getHeaderFields();
    List<String> eTagList = headerFields.get("ETag");
    
  6. 关闭连接

    httpUrlConnection.disconnect();
    

IO流传输

try(InputStream inputStream = httpURLConnection.getInputStream();
    BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
    RandomAccessFile randomAccessFile = new RandomAccessFile(httpFileName,"rw")){
    randomAccessFile.seek(localFileContentLength);
    byte[] bytes = new byte[BYTE_SIZE];
    int len = -1;
    while ((len = bufferedInputStream.read(bytes)) != -1){
        randomAccessFile.write(bytes,0,len);
    }
} catch(...){
    ...
} finally{
    ...
}
  • 这里就是通过IO流来写入文件的过程
  • InputStream inputStream = httpURLConnection.getInputStream(); BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream); RandomAccessFile randomAccessFile = new RandomAccessFile(httpFileName,"rw")

这三行再try(...),括号中的代码一般放的是对资源的申请,如果{}中的代码出项了异常,()中的资源就会被关闭,这在inputstream和outputstream的使用中会很方便。网上搜索一波后:这是所谓的try-with-resources,自动资源管理,应该意思是括号里的资源,是语句末尾一定确保要关闭的。

Future模式

这里是在学习了敖丙大佬的文章后,尝试写出来的。所以这个Future不就是个画大饼的渣男吗???

废话不多说,直接上敖丙大佬链接https://juejin.cn/post/6950065347227549703

参数

这个是因为在测试的时候那个getContentLength()返回的一直是-1,懵掉了。

然后再短暂的百度后,发现似乎有个参数问题没有注意:

httpConnection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36");

这个User-Agent如果不设置,不就是相当于告诉别人我要爬你了吗?所以我们可以对这个参数做一下设置