由于flutter断点下载文章不怎么多也没有几个案例,找了半天还是在dio案例上找到的花了些冤枉时间。
基于 dio: ^4.0.0
和path_provider: ^2.0.2
实现一个下载大文件的功能
具体下载逻辑尚未完善只是提供一个思路 也参考了:https://blog.csdn.net/qin19930929/article/details/94628973
import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'package:dio/dio.dart';
import 'package:path_provider/path_provider.dart';
class DownloadFile {
/// 用于记录正在下载的url,避免重复下载
static var downloadingUrls = Map<String, CancelToken>();
/// 断点下载大文件
static Future<void> download({
required String url,
required String savePath,
ProgressCallback? onReceiveProgress,
void Function()? done,
void Function(DioError)? failed,
}) async {
int downloadStart = 0;
bool fileExists = false;
File f = File(savePath);
if (await f.exists()) {
downloadStart = f.lengthSync();
fileExists = true;
}
print("开始:$downloadStart");
if (fileExists && downloadingUrls.containsKey(url)) {
return;
}
var dio = Dio();
CancelToken cancelToken = CancelToken();
downloadingUrls[url] = cancelToken;
try {
var response = await dio.get<ResponseBody>(
url,
options: Options(
/// 以流的方式接收响应数据
responseType: ResponseType.stream,
followRedirects: false,
headers: {
/// 分段下载重点位置
"range": "bytes=$downloadStart-",
},
),
);
File file = File(savePath);
RandomAccessFile raf = file.openSync(mode: FileMode.append);
int received = downloadStart;
int total = await _getContentLength(response);
Stream<Uint8List> stream = response.data!.stream;
StreamSubscription<Uint8List>? subscription;
subscription = stream.listen(
(data) {
/// 写入文件必须同步
raf.writeFromSync(data);
received += data.length;
onReceiveProgress?.call(received, total);
},
onDone: () async {
downloadingUrls.remove(url);
await raf.close();
done?.call();
},
onError: (e) async {
await raf.close();
downloadingUrls.remove(url);
failed?.call(e as DioError);
},
cancelOnError: true,
);
cancelToken.whenCancel.then((_) async {
await subscription?.cancel();
await raf.close();
});
} on DioError catch (error) {
/// 请求已发出,服务器用状态代码响应它不在200的范围内
if (CancelToken.isCancel(error)) {
print("下载取消");
} else {
failed?.call(error);
}
downloadingUrls.remove(url);
}
}
/// 获取下载的文件大小
static Future<int> _getContentLength(Response<ResponseBody> response) async {
try {
var headerContent =
response.headers.value(HttpHeaders.contentRangeHeader);
print("下载文件$headerContent");
if (headerContent != null) {
return int.parse(headerContent.split('/').last);
} else {
return 0;
}
} catch (e) {
return 0;
}
}
/// 取消任务
static void cancelDownload(String url) {
downloadingUrls[url]?.cancel();
downloadingUrls.remove(url);
}
}
调用案例
void main() {
runApp(TestMyApp());
}
class TestMyApp extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _TestMyAppState();
}
}
class _TestMyAppState extends State<TestMyApp> {
void download() async {
var url = "mp4";
Directory dir = await getApplicationDocumentsDirectory();
var sDCardDir = dir.path;
var savePath = sDCardDir + "/video/1.mp4";
File f = File(sDCardDir + "/video");
if (!await f.exists()) {
new Directory(sDCardDir + "/video").createSync();
}
await DownLoadManage().download(
url: url,
savePath: savePath,
onReceiveProgress: (received, total) {
if (total != -1) {
print("下载1已接收:" +
received.toString() +
"总共:" +
total.toString() +
"进度:+${(received / total * 100).floor()}%");
}
},
done: () {
print("下载1完成");
},
failed: (e) {
print("下载1失败:" + e.toString());
},
);
}
@override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
child: Center(
child: GestureDetector(
onTap: () {
download();
},
child: Container(
width: 150,
height: 150,
color: Colors.red,
),
),
),
);
}
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)