分片下载
所谓分片下载就是要利用多线程的优势,将要下载的文件一块一块的分配到各个线程中去下载,这样就极大的提高了下载速度。
技术难点
并不能说是什么难点,只能说没接触过不知道罢了。
1、如何请求才能拿到数据的特定部分,而非全部?
可以在HTTP请求头中加入Range来标识数据的请求范围/区间,从HTTP/1.1开始可用。
基本用法:
Range: bytes=10-
:取第10个字节及后所有数据。
Range: bytes=40-100
:取第40个字节到第100个字节之间的数据。
这样我们就能拿到特定部分的数据了,断点续传也可以用这个来实现。
PS:0为开始点。
2、分片后某线程下载时如何写出?
思路1:等所有下载完成后进行统一汇总整理然后再一次性写出。
这简直是最笨的思路了,如果文件过大全部拉到内存中,岂不凉凉。
思路2:下载采用多线程,写出时采取数据前后顺序排队写出。
也就是说多线程下载,单线程输出,某种程度解决了内存占用问题,不过效率基本不理想。
思路3:要说还是API香,老大哥Java给我们提供了一个类叫做RandomAccessFile
。
这个类可以进行随机文件读写,其中有一个seek函数,可以将指针指向任意位置,然后进行读写。什么意思呢,举个栗子:假如我们开了30个线程,首先第一个下载完成的是线程X,它下载的数据范围是4000-9000,那么这时我们调用seek函数将指针拨动到4000,然后调用它的write函数将byte写出,这时4000之前都是NULL,4000之后就是我们插入的数据。这样就可以实现多线程下载和本地写入了。
具体实现
分片下载类,我们需要创建多个对象来进行下载。
public class MultipleThreadDownloadManager implements Runnable {
private String uri;
private File target;
public MultipleThreadDownloadManager(String uri, File target) {
this.target = target;
this.uri = uri;
}
/**
* 开始下载
*/
public void start() {
if (target.exists() == false) {
try {
target.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
new Thread(this).start();
}
/**
* 根据文件总大小计算