# thunder
**Repository Path**: hztv/thunder
## Basic Information
- **Project Name**: thunder
- **Description**: 一个简单、快速、可扩展的多任务 多线程下载器
- **Primary Language**: Java
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 3
- **Created**: 2025-01-05
- **Last Updated**: 2025-01-05
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
## Thunder
> 一个简单、快速、可扩展的多任务 _多线程下载器_
#### 环境
+ Jdk11
+ Maven3.8.x
#### 支持协议
+ Http/1.1
#### 简单示例
+ 极简启动
```java
Thunder.me()
.schedule("https://ks-xpc4.xpccdn.com/5117a9fe-df5b-4670-90fb-87911b28a7e0.mp4", "D:\\mydd\\张国荣.mp4")
.schedule("https://ks-xpc4.xpccdn.com/fe8f0e83-8d83-474d-8642-43dbf616684c.mp4", "D:\\mydd\\微博钱包.mp4")
.schedule("https://ks-xpc17.xpccdn.com/82bbe85d-0683-4af3-91e8-cb3621f93f1f.mp4", "D:\\mydd\\五月天走心纪录短片.mp4")
.schedule("https://ks-xpc4.xpccdn.com/b9a664a9-8f02-46cb-85e4-08c5e6d217eb.mp4", "D:\\mydd\\1500棵樱花共同绽放.mp4")
.schedule("https://ks-xpc4.xpccdn.com/ad25a35b-bbe2-4212-8d96-4ce0d0203206.mp4", "D:\\mydd")
.run();
```
+ 单线程下载
```java
Thunder.me()
// 这里代表单线程下载
.single()
.schedule("https://ks-xpc4.xpccdn.com/5117a9fe-df5b-4670-90fb-87911b28a7e0.mp4", "D:\\mydd\\张国荣.mp4")
.schedule("https://ks-xpc4.xpccdn.com/fe8f0e83-8d83-474d-8642-43dbf616684c.mp4", "D:\\mydd\\微博钱包.mp4")
.run();
```
+ 指定线程数
```java
Thunder.me()
// 启动100个线程
.multi(100)
.schedule("https://ks-xpc4.xpccdn.com/5117a9fe-df5b-4670-90fb-87911b28a7e0.mp4", "D:\\mydd\\张国荣.mp4")
.run();
```
+ 指定切片数或切片大写(注意!两者不能同时存在,后面的会覆盖前面)
```java
Thunder.me()
// 切片2个
.sharingNum(2)
.schedule("https://ks-xpc4.xpccdn.com/5117a9fe-df5b-4670-90fb-87911b28a7e0.mp4", "D:\\mydd\\张国荣.mp4")
.run();
// 或者指定切片大小
Thunder.me()
.sharingUnitByKB(1024 * 1024 * 2L)
.schedule("https://ks-xpc4.xpccdn.com/5117a9fe-df5b-4670-90fb-87911b28a7e0.mp4", "D:\\mydd\\张国荣.mp4")
.run();
```
+ 指定切片重试次数
```java
Thunder.me()
.reties(3L)
.schedule("https://ks-xpc4.xpccdn.com/5117a9fe-df5b-4670-90fb-87911b28a7e0.mp4", "D:\\mydd\\张国荣.mp4")
.run();
```
#### 与Giee上其他多线程下载器对比 (仅供参考)
+ 选取对比的下载器地址:[fast-download](https://gitee.com/silently9527/fast-download)
+ 以下本项目称为: **Thunder**, 对比的下载器称为:**FastDownload**
###### **速度**
1. 大文件对比
| 文件地址 | 大小 |
| --- | --- |
| [http://mirrors.163.com/centos/8-stream/isos/x86_64/CentOS-Stream-8-x86_64-20210728-dvd1.iso](http://mirrors.163.com/centos/8-stream/isos/x86_64/CentOS-Stream-8-x86_64-20210728-dvd1.iso) | 9.61(GB) |
+ **Thunder**
+ 线程数:50
+ 耗时:884184ms (884.184s)
+ 
+ **FastDonwload**
+ 线程数:50
+ 耗时:914s
+ 
2. 小文件对比
| 文件地址 | 大小 |
| --- | --- |
| [https://ks-xpc4.xpccdn.com/5117a9fe-df5b-4670-90fb-87911b28a7e0.mp4](https://ks-xpc4.xpccdn.com/5117a9fe-df5b-4670-90fb-87911b28a7e0.mp4) | 35.68(MB) |
+ **Thunder**
+ 线程数:1
+ 耗时:3629ms (3.629s)
+ **FastDownload**
+ 线程数:1
+ 耗时: 3s
可以看到,速度方面是差不多的。
###### **API设计**
+ **Thunder** 统一管理
+ 支持单线程
+ 支持设置线程数
+ 支持设置切片数
+ 支持设置切片大小
+ 支持重试
+ 支持自定义切片算法
+ 支持自定义数据写入方式
+ 支持错误回调
+ 支持多地址
……
```java
Thunder.me()
.sharingNum(1)
.sharingUnitByKB(1024)
.single()
.multi(50)
.reties(3L)
.downloadHandler(new DefaultDownloadHandler() {
@Override
public List partition(long id, long size, boolean isRange, String address) {
// 你的逻辑
return null;
}
})
.schedule("https://ks-xpc4.xpccdn.com/5117a9fe-df5b-4670-90fb-87911b28a7e0.mp4", "D:\\mydd\\张国荣.mp4")
.schedule("https://ks-xpc4.xpccdn.com/fe8f0e83-8d83-474d-8642-43dbf616684c.mp4", "D:\\mydd\\微博钱包.mp4")
.run();
```
+ **FastDownload** 多个不同实例
+ 支持单线程
+ 支持设置线程数
+ 支持自定义进度打印
+ 支持单线程,内存缓存依次写入
```java
String fileURL = "";
// 内存写
SimpleDownloader simpleDownloader = new SimpleDownloader();
simpleDownloader.download(fileURL, "D:\\Video");
//单线程下载
Downloader downloader = new FileDownloader();
downloader.download(fileURL, "/Users/huaan9527/Desktop");
// 多线程下载,设置线程数据和自定义打印
MultiThreadDownloadProgressPrinter downloadProgressPrinter = new MultiThreadDownloadProgressPrinter(50);
Downloader downloader = new MultiThreadFileDownloader(50, downloadProgressPrinter);
downloader.download(fileURL, "D:\\Video");
```
###### **第三方依赖管理**
+ **Thunder** [无依赖]
+ **FastDownload** [依赖 Spring]
###### **实现差异**
+ **Thunder**
+ 默认,大小文件、多单线程数据写入都采用同一个文件随机写入。
+ **FastDownload**
+ 默认,大文件、多线程每个线程数据写入临时文件,然后合并所以临时文件。
+ 默认,小文件、单线程先缓存内存,然后依次同一个文件。(必须是单线程,确保写入顺序)
>Tips:
如果Thunder要实现内存缓存、多临时文件合并也很简单,如实现内存缓存代码:
```java
// 实现内存缓存代码。目前已内置
public class MemoryDownloadHandler extends DefaultDownloadHandler {
private final ConcurrentHashMap dataCache = new ConcurrentHashMap<>();
@Override
public void data(InputStream inputStream, DownloadTask downloadTask, ShardingTask shardingTask) throws Exception {
byte[] bytes = inputStream.readAllBytes();
dataCache.put(shardingTask.getOffset(), bytes);
System.out.println("[下载完成@" + shardingTask.getId() + "#" + shardingTask.getOffset() + "] - " + shardingTask);
}
@Override
public void completed(DownloadTask task) {
final Path path = Paths.get(task.getLocation());
dataCache.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.map(Map.Entry::getValue)
.forEach(bytes -> {
try {
Files.write(path, bytes, StandardOpenOption.CREATE, StandardOpenOption.APPEND);
} catch (IOException e) {
// ignore
}
});
dataCache.clear();
super.completed(task);
}
}
// 创建下载器
Thunder.me()
// 使用内存模式,防止内存溢出和数据混乱
.memoryCacheMode()
.downloadHandler(new MemoryDownloadHandler())
.schedule("https://ks-xpc4.xpccdn.com/5117a9fe-df5b-4670-90fb-87911b28a7e0.mp4", "D:\\Video\\aa.mp4")
.run();
// 注意,与FastDownload不同的是:
// 1、依旧是多线程
// 2、依旧支持多任务
```
## TODO
+ 持久化下载历史
+ 持久化下载点
+ 支持手动重试
+ 支持首次启动下载之前未下载点
+ 优化下载进度显示