负责下载的线程:
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
public class DownloadThread extends Thread {
// 定义字节数组(用于取水的那个竹筒)的长度
private final int BUFF_LEN = 100;
// 定义下载的起始点
private long start;
// 定义下载的结束点
private long end;
// 下载资源对应的输入流
private InputStream inputStream;
// 下载资源对应的输出流
private RandomAccessFile randomAccessFile;
// 构造器:传入起始下载点,结束下载点,输入流,输出流
public DownloadThread (long start,long end,InputStream inputStream,RandomAccessFile randomAccessFile) {
// 打印一下该线程的起始下载点和结束下载点的位置信息
System.out.println(start+" >------> "+end);
this.start = start;
this.end = end;
this.inputStream = inputStream;
this.randomAccessFile = randomAccessFile;
}
@Override
public void run() {
try {
// 记录指针向前移动start个字符
inputStream.skip(start);
// 记录指针定位到start位置处
randomAccessFile.seek(start);
// 定义读取输入流内容的缓存数组(竹筒)
byte[] buff = new byte[BUFF_LEN];
// 本线程负责下载的资源大小
long contentLen = end - start;
// 定义最多需要几次就可以完成本线程的下载任务,方便控制线程的退出
long readMaxTimes = contentLen/BUFF_LEN + 4;
// 实际读取的字节数
int reallyReadCount = 0;
for (int i = 0; i < readMaxTimes; i++) {
// 读取数据
reallyReadCount = inputStream.read(buff);
// 如果读取的字节数小于0,说明读取完毕,则退出循环
if (reallyReadCount < 0) {
break;
}
// 写入数据
randomAccessFile.write(buff, 0, reallyReadCount);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 使用finally块来关闭当前线程的输入流和输出流
try {
if (inputStream != null) {
inputStream.close();
}
if (randomAccessFile != null) {
randomAccessFile.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
传入Url地址,开启下载:
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
public class MultiDownload {
public static void main(String[] args) {
// 定义开启的线程数
final int DOWNLOAD_THREAD_NUM = 4;
// 定义下载文件的文件名,包括后缀
final String OUTPUT_FILE_NAME = "baidu.gif";
// 定义一个DOWNLOAD_THREAD_NUM大小的输入流数组
InputStream[] inArrays = new InputStream[DOWNLOAD_THREAD_NUM];
// 定义一个DOWNLOAD_THREAD_NUM大小的输出流数组
RandomAccessFile[] outArrays = new RandomAccessFile[DOWNLOAD_THREAD_NUM];
try {
// 创建一个URL对象,参数是我们要下载的资源的地址
URL downloadUrl = new URL("http://www.baidu.com/img/baidu_sylogo1.gif");
// 以该URL对象打开第一个输入流
inArrays[0] = downloadUrl.openStream();
// 获取该网络资源文件的长度
long fileLength = getFileLength(downloadUrl);
// 做一个打印
System.out.println("该网络资源文件的大小:"+fileLength);
// 以输出的文件名创建第一个输出流对象,模式是可读,可写
outArrays[0] = new RandomAccessFile(OUTPUT_FILE_NAME, "rw");
// 创建一个与下载资源文件相同大小的空文件
for (int i = 0; i < fileLength; i++) {
outArrays[0].write(0);
}
// 计算每个线程应该下载的字节数
long everyThreadDownloadSize = fileLength/DOWNLOAD_THREAD_NUM;
// 计算整个下载资源整除后剩下的余数
long otherDownloadSize = fileLength%DOWNLOAD_THREAD_NUM;
// 启动各个线程下载各自规定的读取长度的资源
for (int i = 0; i < DOWNLOAD_THREAD_NUM; i++) {
// 刚才只初始化了第一个输入流和输出流对象,初始化剩下的输入流和输出流对象
if (i != 0) {
inArrays[i] = downloadUrl.openStream();
outArrays[i] = new RandomAccessFile(OUTPUT_FILE_NAME, "rw");
}
// 独立配置最后一个线程的下载参数(该线程负责下载整除后余下的资源)
if (i == DOWNLOAD_THREAD_NUM -1) {
new DownloadThread(i*everyThreadDownloadSize, (i+1)*everyThreadDownloadSize+otherDownloadSize, inArrays[i], outArrays[i]);
} else {
// 配置前几个线程的下载参数
new DownloadThread(i*everyThreadDownloadSize, (i+1)*everyThreadDownloadSize, inArrays[i], outArrays[i]);
}
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
// 根据URL获取该URL所指向的资源文件的长度
private static long getFileLength(URL url) throws IOException{
long length = 0;
URLConnection urlConnection = url.openConnection();
long size = urlConnection.getContentLength();
length = size;
return length;
}
}