Java多线程⽂件分⽚下载实现的⽰例代码
多线程下载介绍
多线程下载技术是很常见的⼀种下载⽅案,这种⽅式充分利⽤了多线程的优势,在同⼀时间段内通过多个线程发起下载请求,将需要下载的数据分割成多个部分,每⼀个线程只负责下载其中⼀个部分,然后将下载后的数据组装成完整的数据⽂件,这样便⼤⼤加快了下载效率。常见的下载器,迅雷,QQ旋风等都采⽤了这种技术。
分⽚下载
所谓分⽚下载就是要利⽤多线程的优势,将要下载的⽂件⼀块⼀块的分配到各个线程中去下载,这样就极⼤的提⾼了下载速度。
技术难点
并不能说是什么难点,只能说没接触过不知道罢了。
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 UnitDownloader implements Runnable {
private int from;
private int to;
private File target;
private String uri;
private int id;
public UnitDownloader(int from, int to, File target, String uri, int id) {
this.from = from;
< = to;
this.target = target;
this.uri = uri;
this.id = id;
}
public int getFrom() {
return from;
}
public int getTo() {
return to;
}
@Override
public void run() {
//download and save data
try {
HttpURLConnection connection = (HttpURLConnection) new URL(uri).openConnection();
connection.setRequestProperty("Range", "bytes=" + from + "-" + to);
int totalSize = ContentLength();
InputStream inputStream = InputStream();
RandomAccessFile randomAccessFile = new RandomAccessFile(target, "rw");
randomAccessFile.seek(from);
byte[] buffer = new byte[1024 * 1024];
int readCount = ad(buffer, 0, buffer.length);
while (readCount > 0) {
totalSize -= readCount;
System.out.println("分⽚:" + this.id + "的剩余:" + totalSize);
randomAccessFile.write(buffer, 0, readCount);
readCount = ad(buffer, 0, buffer.length);
}
inputStream.close();
randomAccessFile.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
分⽚下载管理器,主要就是拿到内容的总⼤⼩,将其分配给每⼀个UnitDownloader。这⾥的threadCount函数可以再考虑优化⼀下。
public class MultipleThreadDownloadManager implements Runnable {
凉凉下载private String uri;
private File target;
public MultipleThreadDownloadManager(String uri, File target) {
this.target = target;
this.uri = uri;
if (ists() == false) {
try {
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 开始下载
*/
public void start() {
new Thread(this).start();
}
/**
* 根据⽂件总⼤⼩计算线程数量
*
* @param totalSize
* @return
*/
public int threadCount(int totalSize) {
if (totalSize < 30 * 2014 * 1024) {
return 1;
}
return 30;
}
@Override
public void run() {
//获取⽂件总⼤⼩
int totalSize = 0;
try {
HttpURLConnection connection = (HttpURLConnection) new URL(uri).openConnection();
int contentLength = ContentLength();
totalSize = contentLength;
} catch (IOException e) {
e.printStackTrace();
}
//将⽂件分⽚并分开下载
int threadCount = threadCount(totalSize);
int perThreadSize = totalSize / threadCount;//每⼀个线程分到的任务下载量
int id = 0;
int from = 0, to = 0;
while (totalSize > 0) {
id++;
//计算分⽚
if (totalSize < perThreadSize) {
from = 0;
to = totalSize;
} else {
from = totalSize;
to = from + perThreadSize;
}
/
/开始下载
UnitDownloader downloader = new UnitDownloader(from, to, target, uri, id);
new Thread(downloader).start();
}
}
}
参考⽂献
到此这篇关于Java多线程⽂件分⽚下载实现的⽰例代码的⽂章就介绍到这了,更多相关Java多线程分⽚下载内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!