小白自学到多线程,突发奇想,现在的网络下载工具都不怎么好用。
自己有时候还使用爬虫,就写了下基于http协议的多线程下载。
不到之处,还请各位谅解。
思路是:
1)先完成单线程下载
2)将单线程修改为多线程下载
单线程的例子我就不列举了,直接放多线程的,一共有两个类:下载文件工具类,和个人线程类
/**
* 下载文件工具类
* Created by sumei on 17/8/8.
*/
public class DownUtil {
/**
*
* 通过http协议从网络中下载文件到指定的目录下
* @param urlPath 网络资源地址
* @param targetPath 下载到指定目录的地址
* @param targetName 下载文件 , 指定文件名
* @param threadCount 线程总数,通过线程总数计算所需下载文件的大小
* @param threadNo 线程编号,通过计算获得所下载的文件对应的位置
*/
public static void download ( String urlPath , String targetPath , String targetName , int threadCount , int threadNo ) {
InputStream in = null;
RandomAccessFile saf = null;
try {
// 初始化URL
URL url = new URL(urlPath);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// 获取文件的总大小
long fileSize = conn.getContentLengthLong();
long length = fileSize / threadCount;
long begin = threadNo * length;
long end = threadCount - 1 != threadNo ? begin + length : fileSize ;
// 设置响应时长
conn.setConnectTimeout( 5 * 1000 );
// 获得网络资源的url
in = conn.getInputStream();
// 跳过指定的位置
in.skip(begin);
File file = new File(targetPath);
if ( !file.exists() ) {
file.mkdirs();
}
// 创建输出流
saf = new RandomAccessFile( targetPath + targetName , "rw");
// 从文件的指定位置开始输出
saf.seek(begin);
int len;
byte[] buf = new byte[ 1024 * 8 ];
// 判断
long count = begin ;
while ( -1 != ( len = in.read(buf) ) && count < end) {
count += len;
saf.write( buf , 0 , len );
}
System.out.println("线程" + threadNo + "文件下载成功," + ( count - begin ) );
} catch (IOException e) {
e.printStackTrace();
} finally {
if ( null != in ) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if ( null != saf ) {
try {
saf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
以下是:个人线程类
/**
* 继承Thread类,实现个人线程类
* Created by sumei on 17/8/8.
*/
public class DownThread extends Thread{
// 线程编号
private int threadNo;
// 线程总数
private int threadCount;
// 网络资源地址
private String srcPath;
// 下载文件的指定文件名
private String targetName;
// 下载的文件目录
private String targetPath;
public DownThread(int threadNo, int threadCount, String srcPath, String targetName, String targetPath) {
this.threadNo = threadNo;
this.threadCount = threadCount;
this.srcPath = srcPath;
this.targetName = targetName;
this.targetPath = targetPath;
}
@Override
public void run() {
DownUtil.download(srcPath,targetPath,targetName,threadCount,threadNo);
}
}
测试代码:小部分的,写在main方法中。想尝试的同学,还需要定义targetName,url,和targetPath.
分别是下载文件url路径,下载文件到硬盘的路径目录,和新文件名。
// 个人喜欢 5 个 线程
int threadCount = 5;
for ( int i = 0 ; i < threadCount ; i++ ) {
// 创建线程,开始启动
new DownThread(i,threadCount,url,targetName,targetPath).start();
}
不到之处,请大家指出,勉励,共同进步。