多线程下载 - 如何在服务器不返回Content-Length的情况下获得网络文件大小

最近在写一个项目啊,要从Github上面搬文件下来。文件很大,那么肯定要搬出传统艺能多线程下载——提一嘴,Java中实现多线程下载其实不用那么麻烦,把InputStream集合到ArrayList里转换成平行流,在平行流里完成下载就好了(源码我放到最后)。

现在问题来了:文件很大,服务器用的是——

Transfer-Encoding: chunked

也就是说,服务器不会返回Content-Length。没有Content-Length,也就没有文件大小。没有文件大小,我就不能切片下发给每个线程去完成下载,那怎么办呢?

友利奈绪.jpg
友利奈绪.jpg

这时候,我注意到文档里面有这么一段:

HTTP 请求范围 - HTTP | MDN

什么意思呢?就是,你只要给服务器发送的请求头中有Range请求且服务器支持(大部分都支持,因为很多客户端需要多线程下载)时,服务器在响应头内就会回复一个content-range,其格式为:

content-range: bytes [切片开始位置]-[切片结束位置]/[文件总大小]

看见[文件总大小]了没?那个就是和你要的Content-Length等效的东西。

举个例子:

CMD里输入:
curl http://114514.cn/ -i -H "Range: bytes=0-1"

输出:
HTTP/1.1 206 Partial Content
...
Content-Length: 2
Content-Range: bytes 0-1/996
...

虽然这个有Content-Length,不过实验品嘛,没关系,权当看不见。

看到那个“996”了没?像不像社畜的你?这个就是总大小。但是可能你会说“不对啊,Content-Length是2,而Content-Range却说有996个bytes啊?”

这是因为,看见“/996”前面的“0-1”了嘛?你在请求的时候只请求了0 byte - 1 byte 这个切片,自然也只返回了第0个和第1个字节,加起来是两个。也就是说,Content-Length只会报告当前包有多少个字符,而Content-Range报告的总字节数是无视切割的,会返回总的字节数。

不放心?那就这样:

CMD里输入:
curl http://114514.cn/ -i -H "Range: bytes=0-"

输出:
HTTP/1.1 206 Partial Content
...
Content-Length: 996
Content-Range: bytes 0-995/996
...

为了节省服务器消耗,每次请求的时候,只用请求Range: bytes=0-0就行了。 

然后用正则表达式把文件总大小抓出来,这样就可以下发给线程了——而且完全不用担心416捏。


然后这里是多线程下载的Java源码。

//如果是二进制文件请把BufferedReader换成BufferedInputStream
//把BufferedWriter换成BufferedOutputStream
//把StringBuilder换成byte[]

//前面准备:将每个切片的范围生成好,然后按照范围生成threadCount(见下)个HttpURLConnection。

int threadCount = ...    //线程个数。
ArrayList<BufferedReader> ins = new ArrayList<>(threadCount);
ins.add(...);    //将每个切片的HttpURLConnection的getInputStream转换成Reader加到ins里。

StringBuilder sb = new StringBuilder(threadCount);
//利用平行流完成多线程下载。
ins.parallelStream().forEach((in) -> {
    String str;
    try {
        while ((str = in.readLine()) != null) {
            sb.append(str);
        }
    } catch (IOException exc) {
        throw new RuntimeException(exc);
    }
});

BufferedWriter out = new BufferedWriter(new FileWriter(to));
out.write(sb.toString());

 

明天疯狂星期四,v我老婆50,麻溜的
明天疯狂星期四,v我老婆50,麻溜的

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值