Flutter Windows应用Zip解压时UI更新及大文件处理问题
问题解决:Dart Windows安装程序解压优化(UI响应+大文件处理)
针对UI冻结问题
当前代码里的extractArchiveToDisk是同步阻塞操作,直接在主线程执行会卡住UI。别用Stream/Future直接包裹整个函数,而是把解压逻辑放到后台Isolate执行,通过消息通道向主线程发送进度,这样主线程能实时更新UI不卡顿。
针对大文件崩溃问题
readAsBytes()会把整个文件加载到内存,200MB的文件容易触发内存溢出。改用archive_io的流式API,通过InputFileStream分块读取,避免一次性占用过多内存。
修改后的完整代码
import 'dart:isolate'; import 'package:archive_io/archive_io.dart'; // 主线程调用这个方法启动解压,同时监听进度 void startExtractWithProgress(String zipPath, String targetDir, Function(double progress) onProgress) async { final receivePort = ReceivePort(); // 启动后台Isolate执行解压 await Isolate.spawn( _extractInIsolate, _IsolateParams( zipPath: zipPath, targetDir: targetDir, sendPort: receivePort.sendPort, ), ); // 监听Isolate发来的进度消息 receivePort.listen((message) { if (message is double) { onProgress(message); } else if (message == 'done') { receivePort.close(); } }); } // 后台Isolate里执行的解压逻辑 void _extractInIsolate(_IsolateParams params) { final inputStream = InputFileStream(params.zipPath); final archive = ZipDecoder().decodeBuffer(inputStream); // 计算总文件大小,用于进度计算 int totalSize = archive.files.fold(0, (sum, file) => sum + (file.size ?? 0)); int extractedSize = 0; for (var file in archive.files) { if (!file.isFile) continue; final filePath = '${params.targetDir}/${file.name}'; final outputStream = OutputFileStream(filePath); file.writeContent(outputStream); outputStream.close(); // 更新已提取大小,计算进度 extractedSize += file.size ?? 0; final progress = totalSize > 0 ? extractedSize / totalSize : 1.0; params.sendPort.send(progress); } params.sendPort.send('done'); } // 用于传递Isolate参数的类 class _IsolateParams { final String zipPath; final String targetDir; final SendPort sendPort; _IsolateParams({required this.zipPath, required this.targetDir, required this.sendPort}); }
使用示例
// 在UI层调用 startExtractWithProgress( "C:\\Users\\myUser\\Desktop\\compressedFile.zip", "C:\\Users\\myUser\\Desktop\\extracted", (progress) { // 这里更新UI,比如进度条 print('解压进度:${(progress * 100).toStringAsFixed(1)}%'); }, );
关键说明
- Isolate隔离:把解压的CPU密集型操作放到后台Isolate,主线程只负责UI更新,彻底解决冻结问题。
- 流式处理:全程用
InputFileStream和OutputFileStream,文件分块读写,不会一次性加载整个文件到内存,解决大文件崩溃问题。 - 进度计算:通过遍历归档文件,累加已提取大小计算实时进度,通过SendPort发送到主线程更新UI。
内容的提问来源于stack exchange,提问作者Shadi Aslan
相关产品推荐
相关产品推荐

