Flutter sqflite数据库备份失败,报PathNotFoundException错误求助
修复Flutter Sqflite备份与恢复功能的方案
错误原因
抛出的PathNotFoundException核心问题是:备份/恢复时使用的文件路径不匹配,要么是备份时未正确生成备份文件,要么是恢复时指向了错误的路径(比如尝试从cache/databases读取不存在的文件)。
具体修复步骤
1. 修正备份方法的路径逻辑
备份时要确保从正确的原数据库路径读取,并写入到存在的目录中:
import 'dart:io'; import 'package:path_provider/path_provider.dart'; import 'package:sqflite/sqflite.dart'; class DatabaseHelper { Database? _database; static final DatabaseHelper instance = DatabaseHelper._privateConstructor(); DatabaseHelper._privateConstructor(); Future<void> backupDatabase() async { // 获取原数据库的默认存储路径 final dbDirectory = await getDatabasesPath(); final originalDbFile = File('$dbDirectory/habit_tracker.db'); // 选择备份存储目录,这里用外部下载目录(用户易找到) final externalDir = await getExternalStorageDirectory(); if (externalDir == null) throw Exception("无法访问外部存储"); // 确保备份目录存在 await externalDir.create(recursive: true); final backupFile = File('${externalDir.path}/habit_tracker_backup.db'); // 执行备份复制 await originalDbFile.copy(backupFile.path); } }
2. 修正恢复方法的路径匹配
恢复时要指向备份时生成的文件路径,同时注意先关闭数据库连接避免文件占用:
Future<void> restoreDatabase() async { // 目标数据库路径 final dbDirectory = await getDatabasesPath(); final targetDbFile = File('$dbDirectory/habit_tracker.db'); // 备份文件路径(和备份时一致) final externalDir = await getExternalStorageDirectory(); if (externalDir == null) throw Exception("无法访问外部存储"); final backupFile = File('${externalDir.path}/habit_tracker_backup.db'); // 检查备份文件是否存在 if (!await backupFile.exists()) { throw FileSystemException("备份文件不存在"); } // 关闭当前数据库连接,避免文件被占用 await _database?.close(); // 执行恢复复制 await backupFile.copy(targetDbFile.path); // 重新打开数据库 _database = await openDatabase(targetDbFile.path); }
3. 完善权限配置
- AndroidManifest.xml 中添加存储权限:
<manifest ...> <!-- Android 10及以下需要的写入权限 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- Android 11+访问公共目录需要的权限 --> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> <!-- 读取外部存储权限 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <application ...> ... </application> </manifest>
- pubspec.yaml 添加权限处理依赖:
dependencies: flutter: sdk: flutter cupertino_icons: ^1.0.2 path_provider: ^2.0.13 sqflite: ^2.2.8+4 permission_handler: ^10.2.0 # 新增权限处理包
- 代码中动态申请权限(在调用备份/恢复前执行):
import 'package:permission_handler/permission_handler.dart'; Future<bool> requestStoragePermission() async { if (await Permission.storage.request().isGranted) { return true; } else if (await Permission.storage.request().isPermanentlyDenied) { openAppSettings(); return false; } return false; }
4. 关键注意事项
- 操作文件前必须确保目标目录存在,用
create(recursive: true)递归创建目录; - 恢复时必须关闭当前数据库连接,否则会因文件占用导致复制失败;
- 避免使用cache目录存储备份文件(cache目录可能被系统清理),优先选择外部存储的稳定目录(如下载、文档目录)。
内容的提问来源于stack exchange,提问作者mesh
相关产品推荐
相关产品推荐

