最近在做一个下载文件的功能的时候,因为要支持断点续传,虽然整体上思路很清晰,也比较简单,但是在做的过程中还是遇到了几个坑,特意在此记录一下,也重新梳理下下载断点续传的实现过程。 这里先把几个坑点先说明一下: 如果你写入文件用的是FileOutputStream,那么一定要用两参的构造方法: 当你用方法1(通过inputStream的skip)去实现断点续传的时候,skip方法有坑,简单来说就是skip方法不能保证一定会跳过你指定的字节数,所以你自己要做一个简单处理: 当你用方法2(http range header)去实现断点续传的时候,有如下三个坑: 首先要确保服务器支持断点续传,我当时就是因为从网上先随便找个文件来下载,一些文件的服务器是不支持的,导致我调试了好久好久。。。那么怎么判断服务器是否支持呢? 当然是问服务器的同学啦,如果他们也不确定的话(又一个坑~),求人不如求己,可以通过如下命令查看: 看它返回的数据 如果也Content-Range 和 Accept-Ranges,那说明支持,否则就别费劲了,用方法1吧。 第二个坑点是,给request设置header的时候,代码如下: 一定不能缺少最后的那个”-“,否则这个就是个无效的header。 第三个坑点是,当你给你的request添加了这个header之后,你要计算下载百分比吧,我之前计算百分比的分母(即文件大小)的时候,用的是Content-length里返回的数据,那么问题就来了,当你断点续传的时候,返回的数据流里不是所有数据的大小,所以content-length肯定就变小了,这时你在计算百分比肯定就错误了(好吧,这是我自己的问题),解决办法有两个,第一个还是每次都取content-length,但是不能直接用来做分母,要和本地文件的大小做一个加和;第二个就是服务器直接在反水的数据里告诉你文件大小,不取content-length。 这里我还用了OKhttp做网络请求。 优点:不依赖服务器的支持,完全端上自己实现; 优点:节省流量,已经下载过的数据不再下载了,真正的断点续传;一、要注意的地方
1. 追加文件
```java new FileOutputStream(file,true); // 第二个参数为true ```
2. 跳过输入流
private void skip(InputStream in, long offset) throws IOException { long skip = 0; do { offset -= skip; skip = in.skip(offset); if (skip <= 0) { break; } } while (skip != offset); }
3.range header
坑点1.
curl -i --range 100-200 http://app.znds.com/down/20200331/w2zry_1.53.1.6_dangbei.apk
HTTP/1.1 206 Partial Content Server: JSP3/2.0.14 Date: Fri, 24 Apr 2020 04:21:54 GMT Content-Type: application/vnd.android.package-archive Content-Length: 101 Connection: keep-alive ETag: "7629026C24EBCA9B219A6BEC4DA7E475" Last-Modified: Tue, 31 Mar 2020 08:02:33 GMT Age: 863675 Content-Range: bytes 100-200/393647401 Accept-Ranges: bytes x-oss-request-id: 5E82FA10146F3833363BA5BA x-oss-object-type: Normal x-oss-hash-crc64ecma: 14417895789503488492 x-oss-storage-class: Standard Content-MD5: dikCbCTrypshmmvsTafkdQ== x-oss-server-time: 9 Ohc-File-Size: 393647401 Timing-Allow-Origin: * Ohc-Cache-HIT: cangzuncache63 [4], qdix131 [3]
坑点2
header("Range", "bytes=" + offset + "-")
坑点3.
二、代码
下面两种方法我都是自己传进来了文件的大小,如果不想自己传的话,下面的size可以改成,contentLength自己去获取吧。long size = contentLength + offset;
方法1
缺点:会浪费流量;public void download(final String url, final String path, long offset, long size, final OnDownloadListener listener) { Request request = new Request.Builder() .url(url) .build(); downloadCall = okHttpClient.newCall(request); downloadCall.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { // 下载失败 listener.onDownloadFailed(1); } @Override public void onResponse(Call call, Response response) { listener.onDownloadStart(); InputStream is = null; byte[] buf = new byte[2048]; int len = 0; FileOutputStream fos = null; try { is = response.body().byteStream(); // 跳过offset文件大小 skip(is,offset); File file = new File(path); fos = new FileOutputStream(file, true); long sum = offset; while ((len = is.read(buf)) != -1) { fos.write(buf, 0, len); sum += len; Log.d("downloadtUtil", "download length:" + sum); int progress = (int) (sum * 1.0f / size * 100); // 下载中 listener.onDownloading(progress); } fos.flush(); // 下载完成 listener.onDownloadSuccess(); } catch (SocketException e) { e.printStackTrace(); listener.onDownloadFailed(1); } catch (IOException e) { e.printStackTrace(); listener.onDownloadFailed(0); } finally { try { if (is != null) { is.close(); } } catch (IOException e) { } try { if (fos != null) { fos.close(); } } catch (IOException e) { } } } }); }
方法2
缺点:依赖服务器配置或者服务器开发人员开发;public void download(final String url, final String path, long offset, long size, final OnDownloadListener listener) { Request request = new Request.Builder() .header("Range", "bytes=" + offset + "-") .url(url) .build(); downloadCall = okHttpClient.newCall(request); downloadCall.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { // 下载失败 listener.onDownloadFailed(1); } @Override public void onResponse(Call call, Response response) { HLog.d("http request:" + response.request().headers()); HLog.d("http request:" + response.headers()); listener.onDownloadStart(); InputStream is = null; byte[] buf = new byte[2048]; int len = 0; FileOutputStream fos = null; // 储存下载文件的目录 try { is = response.body().byteStream(); File file = new File(path); fos = new FileOutputStream(file, true); long sum = offset; while ((len = is.read(buf)) != -1) { fos.write(buf, 0, len); sum += len; Log.d("downloadtUtil", "download length:" + sum); int progress = (int) (sum * 1.0f / size * 100); // 下载中 listener.onDownloading(progress); } fos.flush(); // 下载完成 listener.onDownloadSuccess(); } catch (SocketException e) { e.printStackTrace(); listener.onDownloadFailed(1); } catch (IOException e) { e.printStackTrace(); listener.onDownloadFailed(0); } finally { try { if (is != null) { is.close(); } } catch (IOException e) { } try { if (fos != null) { fos.close(); } } catch (IOException e) { } } } }); }
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算