Flutter iOS端如何取消本地文件复制且无需删除副本
问题解答
首先明确:不存在无需删除副本就能直接取消文件复制的方法。
原因在于Dart的File.copy()方法本质是将复制操作委托给底层操作系统执行,一旦发起请求,操作系统会独立完成整个复制流程。Dart层面的CancelableOperation只能取消对复制结果Future的监听,无法中断底层正在进行的系统复制进程——这就导致哪怕你调用了cancel(),目标文件仍然会被创建(可能是空白文件,也可能是复制了一部分内容的不完整文件)。
如果想要避免留下无效的副本,你需要自己实现分块复制的逻辑,在每一步复制时检查取消信号,一旦触发取消就停止写入并清理目标文件。以下是具体实现示例:
import 'dart:io'; import 'package:async/async.dart'; CancelableOperation? _currentCopyOp; File? _targetFile; // 启动文件复制 void startCopy(String sourcePath, String targetPath) { _targetFile = File(targetPath); _currentCopyOp = CancelableOperation.fromFuture( _chunkedCopy(sourcePath, targetPath), onCancel: () async { // 取消时删除不完整的目标文件 await _targetFile?.delete(); _targetFile = null; }, ); } // 分块复制逻辑 Future<void> _chunkedCopy(String sourcePath, String targetPath) async { const chunkSize = 8192; // 按8KB分块复制 final sourceStream = File(sourcePath).openRead(); final writeSink = File(targetPath).openWrite(); try { await for (final chunk in sourceStream) { // 每块复制前检查是否已取消 if (_currentCopyOp?.isCanceled ?? false) { throw CanceledError(); } await writeSink.addStream(Stream.value(chunk)); } await writeSink.close(); } catch (e) { await writeSink.close(); rethrow; } finally { await sourceStream.drain(); } } // 取消复制 void cancelCopy() async { await _currentCopyOp?.cancel(); _currentCopyOp = null; }
这个实现的核心思路是:
- 将大文件拆分成小块逐步读取和写入
- 在每一块写入前检查取消状态,若已取消则终止流程
- 利用
CancelableOperation的onCancel回调在取消时删除不完整的目标文件
需要注意的是:只要复制操作已经开始写入目标文件,就必然会创建文件实体,没有办法完全避免副本的创建——我们能做的只是在取消时及时清理掉无效的副本,避免残留垃圾文件。
内容的提问来源于stack exchange,提问作者Max
相关产品推荐
相关产品推荐

