You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter Dio取消下载时文件被删除,求保留文件的解决方法

解决方案:保留Dio取消下载后的已下载文件

Dio自带的download方法通过CancelToken取消时,会自动清理临时下载文件——这是因为它内部采用「先写临时文件、完成后重命名到目标路径」的逻辑。要实现停止下载且保留已下载内容,你可以放弃Dio封装好的download方法,改用手动处理响应流的方式:

方法一:手动分块写入文件,自定义取消逻辑

直接通过Dio获取响应流,自己控制文件写入过程,取消时仅停止流订阅,不会删除已写入的内容:

import 'dart:io';
import 'package:dio/dio.dart';

class DownloadHandler {
  Dio dio = Dio();
  File? targetFile;
  StreamSubscription? streamSubscription;
  bool _cancelFlag = false;

  // 启动下载
  Future<void> start(String downloadUrl, String savePath) async {
    targetFile = File(savePath);
    _cancelFlag = false;

    try {
      // 以流形式获取响应,避免大文件占用内存
      final response = await dio.get(
        downloadUrl,
        options: Options(responseType: ResponseType.stream),
      );

      // 订阅流,分块写入文件
      streamSubscription = response.data.stream.listen(
        (chunk) {
          if (!_cancelFlag) {
            targetFile?.writeAsBytes(chunk, mode: FileMode.append);
          } else {
            streamSubscription?.cancel();
          }
        },
        onDone: () => print("下载完成"),
        onError: (e) => print("下载出错: $e"),
      );
    } catch (e) {
      print("请求初始化失败: $e");
    }
  }

  // 停止下载,保留已下载内容
  void cancel() {
    _cancelFlag = true;
    streamSubscription?.cancel();
    print("下载已停止,已下载内容已保留");
  }
}

关键说明:

  • 用ResponseType.stream获取响应流,避免一次性加载大文件到内存
  • 通过FileMode.append实现分块写入,确保已下载的字节不会丢失
  • 取消时仅标记停止写入并取消流订阅,不会触发Dio内置的文件清理逻辑

注意事项

  • 首次下载前如果目标文件已存在,建议先删除或处理(比如实现断点续传时,可先读取已下载长度,请求时设置Range头)
  • 确保已申请文件存储权限(Android的WRITE_EXTERNAL_STORAGE/MANAGE_EXTERNAL_STORAGE,iOS的NSDocumentDirectory访问权限)
  • 可基于此扩展断点续传:取消后记录已下载文件长度,下次下载时通过Headers.rangeHeader请求剩余部分

内容的提问来源于stack exchange,提问作者ali ma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 08:53:15