多线程实现多线程下载文件

下载文件的时候,一个大文件切成很多片,用多线程下载,速度会快很多

阅读代码的时候注意查看代码里面的注释
想用多线程下载文件,则,

第一:得了解  RandomAccessFile  类,这是个随机访问文件类,里面可以设置 访问的 开始地址和结束地址,且该类可读可写。

RandomAccessFile out = new RandomAccessFile(file, "rw"); 则表示,该类可读可写。通过 out.seek(start)  可以定位开始读取的位置。

第二:既然是网络文件下载,那就必须得了解 URL 类,该类是 java.net 包提供的一个 可以用来网络连接的类。

URL url = new URL(urlLocation); 可以这样实例化该类,然后打开连接,HttpURLConnection conn = (HttpURLConnection) url.openConnection();,还可以设置些别的参数,比如说设置超时,设置访问方法,设置 访问 起始点之类的。

conn.setConnectTimeout(5000);
        conn.setRequestMethod("GET");

conn.setRequestProperty("Range", "bytes=" + start +"-"+end );

第三:了解线程,这里我们使用 java 1.5之后引入的 concurrent 包里面的  Executors.newCachedThreadPool() 线程池

第四:最基本的 io读写得知道

看看代码吧。

1.为了方便,我写了个工具类,用于提供 Util类用来提供获取 HttpURLConnection 连接

public class Util {

// 记录读取了多少,一共读取了多少
public static long start;
// 记录文件总大小
public static long sum;

/**
*
* @Title: getHttpConnection
* @Description: 获取 url 连接
* @param: @param urlLocation
* @param: @return HttpURLConnection实例化对象
* @param: @throws IOException
* @return: HttpURLConnection
* @throws
*/
public static HttpURLConnection getHttpConnection(String urlLocation) throws IOException {
URL url = new URL(urlLocation);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");

return conn;
}
}
2.文件切片,分别指定 起始点,注意这里的起始点是包头也包尾的,0-10/11-20/21-30  这种

public class DownloadFilePool {
// 网络资源路径
private String urlLocation;
// 存储路径
private String filePath;
// 多少个线程
private int poolLength;

public DownloadFilePool(String urlLocation, String filePath, int poolLength) {
super();
// 如果 保存路径为空则默认存在 D盘,文件名跟下载名相同
if( filePath==null ) {
String fileName = urlLocation.substring( urlLocation.lastIndexOf("/") +1);
filePath = "D:/" + fileName;
}

this.urlLocation = urlLocation;
this.filePath = filePath;
this.poolLength = poolLength;
}

public void getFile() {
try {
// 获取文件长度
long fileLength = Util.getHttpConnection(urlLocation).getContentLengthLong();
Util.sum = fileLength;

ExecutorService pool = Executors.newCachedThreadPool();

// 获取每片大小
long slice = fileLength/poolLength;
for(int i = 0 ;i < poolLength; i++) {
long start = i*slice;
long end = (i+1)*slice -1;

if(i==poolLength-1) {
start = i*slice;
end = fileLength ;
}
System.out.println( start + "---" + end );
// 创建下载类
DownloadFileRang downloadFileRang = new DownloadFileRang(start, end, urlLocation, filePath);
// 执行线程
pool.execute(downloadFileRang);
}
// 关闭线程池
pool.shutdown();
} catch (Exception e) {
e.printStackTrace();
}
}
}
3.文件下载类,此处使用 继承 Runnable 实现多线程

public class DownloadFileRang implements Runnable {
// 文件开始位置
private long start ;
// 文件结束位置
private long end;
// url地址
private String urlLocation;
// 文件存储位置
private String filePath;

public DownloadFileRang(long start, long end, String urlLocation, String filePath) {
super();
this.start = start;
this.end = end;
this.urlLocation = urlLocation;
this.filePath = filePath;
}

@Override
public void run() {
try {
// 获取连接
HttpURLConnection conn = Util.getHttpConnection(urlLocation);
// 设置获取资源范围
conn.setRequestProperty("Range", "bytes=" + start +"-"+end );

File file = new File(filePath);
RandomAccessFile out = null;
if(file!=null) {
out = new RandomAccessFile(file, "rw");
}
out.seek(start);

// 获取网络连接的 输入流
InputStream is = conn.getInputStream();

byte [] data = new byte[1024];
int len = 0;
while( (len = is.read(data))!=-1 ) {
out.write(data, 0, len);
synchronized (Util.class) {
Util.start += len;
}
}

// 关闭连接
out.close();
is.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
4.实现显示实时网速

实时网速,其实就是单位时间内,所读取到的 资源,我们这里就是读取到的 len,观察我的代码,可以发现,我在 Util类里面写了两个静态属性,分别是 start 用来记录一共读了多少,一个是 sum,记录总文件大小。

线程类里面的 out.write 方法里面我 用 start 进行累加 len,这就是记录一共读取了多少资源,因为 多线程不能保证数据的原子性,所以我这里累加的时候,为避免因为线程原因出现数据错误,则进行加锁,加上  Util 对象的锁,告诉别的线程,这个 strat 同意时刻内只能一个线程来进行 操作。然后  用 每个时间段,比如说我这里是 500ms ,内读取的资源 / 500ms 就是网速了。

5.调用实例

public static void main(String[] args) {
Date startDate = new Date();

DownloadFilePool pool = new DownloadFilePool("http://fs.w.kugou.com/201809152325/5cbbb70b45431a17cad6ddd6d5342ef5/G108/M03/0C/01/rA0DAFk_VuiALN9DADmXB0zHYTA058.mp3", null, 100);
pool.getFile();

long old = 0;
long now = 0;
while( Util.sum >= Util.start ) {
now = Util.start - old;
old = Util.start;

if(Util.sum == Util.start) {
long t = new Date().getTime() - startDate.getTime();
double speed = ((double)Util.sum / (t/1000.0))/1024.0/1024.0;

System.out.println( "下载完成,用时:" + t/1000.0 +" s 平均网速:" + speed +" M/s" );
break;
}

System.out.println( "网速:" + ((double)(now/0.5))/1024.0/1024.0 +" M/s,已完成:" + (Util.start / (double)Util.sum)*100 +"%" );

try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

运行效果:
---------------------
作者:临窗,听雨声
来源:CSDN
原文:https://blog.csdn.net/yali_aini/article/details/82713368
版权声明:本文为博主原创文章,转载请附上博文链接!

原文地址:https://www.cnblogs.com/sidesky/p/10489854.html

时间: 2024-11-14 15:48:21

多线程实现多线程下载文件的相关文章

多线程从网络下载文件

主类: 1 public class DownThreadDemo { 2 3 public static void main(String[] args) { 4 // TODO Auto-generated method stub 5 int threadNum = 3; 6 long fileLen = 0; 7 long numPerThread = 0; 8 long left = 0; 9 URL url = null; 10 URLConnection connection = n

java多线程下载文件和断点下载

多线程,断点下载文件 import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.RandomAccessFile;

Android 多线程断点续传同时下载多个大文件

最近学习在Android环境中一些网络请求方面的知识,其中有一部分是关于网络下载方面的知识.在这里解析一下自己写的demo,总结一下自己所学的知识.下图为demo的效果图,仿照一些应用下载商城在ListView中列出加载项,然后可以可以下载和停止. 1.概述 这里有几个比较重要的类DownloadManager.DownloadService.DownloadTask.ThreadDAOImpl.主要的下载流程如下. (1) DownloadManager 负责下载任务的调配,以及下载服务Dow

PHP利用Curl实现多线程抓取网页和下载文件

PHP 利用 Curl  可以完成各种传送文件操作,比如模拟浏览器发送GET,POST请求等等,然而因为php语言本身不支持多线程,所以开发爬虫程序效率并不高,一般采集 数据可以利用 PHPquery类来采集数据库,在此之外也可以用 Curl ,借助Curl 这个功能实现并发多线程的访问多个url地址以实现并发多线程抓取网页或者下载文件. 至于具体实现过程,请参考下面几个例子: 1.实现抓取多个URL并将内容写入指定的文件 $urls = array( '路径地址', '路径地址', '路径地址

多线程实现下载文件

一:需求分析 1:下载远程资源文件,通过多线程下载,达到高效的目的. 2:使用5个线程分别下载文件的不同部分. 二:定义成员变量以及初始化变量 1 // 定义成员变量 2 private String path; // 远程资源路径 3 private String targetPath; // 本地存储路径 4 private DownFileThread[] threads; // 线程list 5 private int threadNum; // 线程数量 6 private long

多线程下载文件,以及断点下载

一:前言 多线程下载文件,可能有的同学没有过多的听说过,但是断点下载肯定是听过的,也就是说像讯雷,哪怕你把电脑重启了,讯雷重新启动后也会接着原来的地方下载,那么这是怎么做到的呢? 二:代码示例 直接给出代码, 2.1.经典代码 两行经典的代码分别为: //设置下载的开始及结束位置 conn.setRequestProperty("Range", "bytes="+start+"-"+end+""); //设置读写的起点位置 R

python多线程下载文件

从文件中读取图片url和名称,将url中的文件下载下来.文件中每一行包含一个url和文件名,用制表符隔开. 1.使用requests请求url并下载文件 def download(img_url, img_name): with closing(requests.get(img_url, stream=True)) as r: with open(os.path.join(out_dir, img_name), 'wb') as f: for data in r.iter_content(102

最新---java多线程下载文件

import java.io.InputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL; public class Demo { // 定义线程个数 public static int threadCount = 5; public static void main(String[] args) throws Exception { // 1,连接到服务

多线程下载文件(支持暂停、取消、断点续传)

多线程下载文件(支持暂停.取消.断点续传) 多线程同时下载文件即:在同一时间内通过多个线程对同一个请求地址发起多个请求,将需要下载的数据分割成多个部分,同时下载,每个线程只负责下载其中的一部分,最后将每一个线程下载的部分组装起来即可. 涉及的知识及问题 请求的数据如何分段 分段完成后如何下载和下载完成后如何组装到一起 暂停下载和继续下载的实现(wait().notifyAll().synchronized的使用) 取消下载和断点续传的实现 一.请求的数据如何分段 首先通过HttpURLConne

安卓 多线程下载文件

HTTP文件多线程下载 测试代码 String downloadUrl = "http://192.168.31.162/FileServer/SoftApk/UC-11.5.5.943.apk"; String filepath = PathUtils.getCachePath() + "UC-11.5.5.943.apk"; /** * 多线程下载 * 基于:http://blog.csdn.net/mad1989/article/details/3842146