在ListView.builder中多选文件后实现复制、建文件夹及压缩功能
完整实现方案
以下是基于Flutter的完整实现代码,涵盖文件选中、复制、新建文件夹及压缩功能:
依赖准备
在pubspec.yaml中添加必要依赖:
dependencies: flutter: sdk: flutter path: ^1.8.3 path_provider: ^2.1.1 archive: ^3.4.10
完整代码
import 'dart:io'; import 'package:flutter/material.dart'; import 'package:path/path.dart' as path; import 'package:archive/archive.dart'; import 'package:path_provider/path_provider.dart'; class FileManagerScreen extends StatefulWidget { final List<File> files; // 传入你的文件列表 const FileManagerScreen({super.key, required this.files}); @override State<FileManagerScreen> createState() => _FileManagerScreenState(); } class _FileManagerScreenState extends State<FileManagerScreen> { final Set<File> _selectedFiles = {}; // 切换文件选中状态 void _toggleFileSelection(File file) { setState(() { _selectedFiles.contains(file) ? _selectedFiles.remove(file) : _selectedFiles.add(file); }); } // 复制选中文件到临时目录 Future<List<File>> _copySelectedFiles() async { final tempDir = await getTemporaryDirectory(); final copiedFiles = <File>[]; for (final file in _selectedFiles) { final destPath = path.join(tempDir.path, path.basename(file.path)); final copiedFile = await file.copy(destPath); copiedFiles.add(copiedFile); } return copiedFiles; } // 创建新文件夹 Future<Directory?> _createNewFolder(String folderName) async { final appDocDir = await getApplicationDocumentsDirectory(); final newFolderDir = Directory(path.join(appDocDir.path, folderName)); if (!await newFolderDir.exists()) { await newFolderDir.create(recursive: true); return newFolderDir; } else { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('文件夹 "$folderName" 已存在')), ); } return null; } } // 压缩文件到指定文件夹 Future<void> _compressFilesToFolder(List<File> files, Directory targetFolder) async { final archive = Archive(); // 添加文件到压缩包 for (final file in files) { final fileBytes = await file.readAsBytes(); archive.addFile(ArchiveFile( path.basename(file.path), fileBytes.length, fileBytes, )); } // 生成并保存ZIP文件 final zipBytes = ZipEncoder().encode(archive); if (zipBytes == null) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('压缩失败,请重试')), ); } return; } final zipPath = path.join(targetFolder.path, 'compressed_files.zip'); await File(zipPath).writeAsBytes(zipBytes); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('文件已压缩至:${targetFolder.path}')), ); } } // 执行完整流程:复制 -> 新建文件夹 -> 压缩 Future<void> _handleCopyAndCompress() async { if (_selectedFiles.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('请先选中至少一个文件')), ); return; } // 1. 复制选中文件到临时目录 final copiedFiles = await _copySelectedFiles(); // 2. 弹出输入框获取文件夹名称 final folderName = await showDialog<String>( context: context, builder: (context) => AlertDialog( title: const Text('新建文件夹'), content: TextField( decoration: const InputDecoration(hintText: '输入文件夹名称'), autofocus: true, onSubmitted: (value) => Navigator.pop(context, value.trim()), ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('取消'), ), TextButton( onPressed: () { final controller = (context.widget as AlertDialog).content as TextField; Navigator.pop(context, controller.text.trim()); }, child: const Text('创建'), ), ], ), ); if (folderName == null || folderName.isEmpty) return; // 3. 创建目标文件夹 final targetFolder = await _createNewFolder(folderName); if (targetFolder == null) return; // 4. 压缩文件到目标文件夹 await _compressFilesToFolder(copiedFiles, targetFolder); // 清理临时文件 for (final file in copiedFiles) { await file.delete(); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('文件管理器'), actions: [ if (_selectedFiles.isNotEmpty) TextButton( onPressed: _handleCopyAndCompress, child: const Text('复制并压缩', style: TextStyle(color: Colors.white)), ), ], ), body: ListView.builder( itemCount: widget.files.length, itemBuilder: (context, index) { final file = widget.files[index]; final isSelected = _selectedFiles.contains(file); return ListTile( leading: const Icon(Icons.file_copy), title: Text(path.basename(file.path)), trailing: isSelected ? const Icon(Icons.check_circle, color: Colors.blue) : null, onTap: () => _toggleFileSelection(file), onLongPress: () => _toggleFileSelection(file), ); }, ), ); } }
关键功能说明
- 选中状态管理:用
Set<File>存储选中文件,避免重复选中,点击/长按ListTile切换选中状态。 - 文件复制:将选中文件复制到系统临时目录,避免操作原文件,压缩完成后自动清理临时文件。
- 新建文件夹:通过弹窗输入文件夹名称,在应用文档目录下创建文件夹,若已存在则提示用户。
- 文件压缩:使用
archive包将文件打包为ZIP,保存到新建的文件夹中,压缩完成后给出成功提示。
额外提示
- 若需操作外部存储,需添加对应权限:Android需申请
READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE,iOS需在Info.plist中添加NSFileProviderDomainUsageDescription权限描述,可配合permission_handler包处理权限请求。 - 可根据需求扩展错误处理逻辑,例如捕获文件复制、压缩过程中的异常并给出对应提示。
内容的提问来源于stack exchange,提问作者Faizan Abbas Bangash
相关产品推荐
相关产品推荐

