核心工具类、错误处理和日志系统
This commit is contained in:
parent
9cc9288d6e
commit
8005e21110
@ -10,7 +10,8 @@
|
|||||||
"Bash(flutter test:*)",
|
"Bash(flutter test:*)",
|
||||||
"Bash(flutter build:*)",
|
"Bash(flutter build:*)",
|
||||||
"Bash(flutter clean:*)",
|
"Bash(flutter clean:*)",
|
||||||
"Bash(dart analyze:*)"
|
"Bash(dart analyze:*)",
|
||||||
|
"Bash(dart test:*)"
|
||||||
],
|
],
|
||||||
"deny": [],
|
"deny": [],
|
||||||
"ask": []
|
"ask": []
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:path/path.dart' as path;
|
import 'package:path/path.dart' as path;
|
||||||
|
import 'package:path_provider/path_provider.dart' as path_provider;
|
||||||
import '../errors/app_error.dart';
|
import '../errors/app_error.dart';
|
||||||
import 'logger.dart';
|
import 'logger.dart';
|
||||||
|
|
||||||
@ -12,7 +13,7 @@ class FileUtils {
|
|||||||
/// 获取应用文档目录
|
/// 获取应用文档目录
|
||||||
static Future<Directory> getApplicationDocumentsDirectory() async {
|
static Future<Directory> getApplicationDocumentsDirectory() async {
|
||||||
try {
|
try {
|
||||||
final directory = await getApplicationDocumentsDirectory();
|
final directory = await path_provider.getApplicationDocumentsDirectory();
|
||||||
Logger.debug('获取应用文档目录: ${directory.path}');
|
Logger.debug('获取应用文档目录: ${directory.path}');
|
||||||
return directory;
|
return directory;
|
||||||
} catch (error, stackTrace) {
|
} catch (error, stackTrace) {
|
||||||
@ -28,7 +29,7 @@ class FileUtils {
|
|||||||
/// 获取临时目录
|
/// 获取临时目录
|
||||||
static Future<Directory> getTemporaryDirectory() async {
|
static Future<Directory> getTemporaryDirectory() async {
|
||||||
try {
|
try {
|
||||||
final directory = await getTemporaryDirectory();
|
final directory = await path_provider.getTemporaryDirectory();
|
||||||
Logger.debug('获取临时目录: ${directory.path}');
|
Logger.debug('获取临时目录: ${directory.path}');
|
||||||
return directory;
|
return directory;
|
||||||
} catch (error, stackTrace) {
|
} catch (error, stackTrace) {
|
||||||
@ -44,7 +45,7 @@ class FileUtils {
|
|||||||
/// 获取应用支持目录(用于存储应用数据)
|
/// 获取应用支持目录(用于存储应用数据)
|
||||||
static Future<Directory> getApplicationSupportDirectory() async {
|
static Future<Directory> getApplicationSupportDirectory() async {
|
||||||
try {
|
try {
|
||||||
final directory = await getApplicationSupportDirectory();
|
final directory = await path_provider.getApplicationSupportDirectory();
|
||||||
Logger.debug('获取应用支持目录: ${directory.path}');
|
Logger.debug('获取应用支持目录: ${directory.path}');
|
||||||
return directory;
|
return directory;
|
||||||
} catch (error, stackTrace) {
|
} catch (error, stackTrace) {
|
||||||
|
|||||||
322
lib/core/utils/path_utils.dart
Normal file
322
lib/core/utils/path_utils.dart
Normal file
@ -0,0 +1,322 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
import 'package:path/path.dart' as path;
|
||||||
|
import 'package:path_provider/path_provider.dart' as path_provider;
|
||||||
|
import 'package:uuid/uuid.dart';
|
||||||
|
import '../errors/app_error.dart';
|
||||||
|
import 'logger.dart';
|
||||||
|
|
||||||
|
/// 路径管理工具类
|
||||||
|
/// 提供UUID生成、路径构建、文件命名等路径相关功能
|
||||||
|
class PathUtils {
|
||||||
|
// 私有构造函数,防止实例化
|
||||||
|
PathUtils._();
|
||||||
|
|
||||||
|
static const Uuid _uuid = Uuid();
|
||||||
|
|
||||||
|
/// 生成唯一ID(UUID v4)
|
||||||
|
/// 返回标准的UUID格式字符串
|
||||||
|
static String generateUniqueId() {
|
||||||
|
return _uuid.v4();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 生成短格式唯一ID
|
||||||
|
/// 截取UUID前8位,适合文件名使用
|
||||||
|
static String generateShortId() {
|
||||||
|
return _uuid.v4().substring(0, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 生成基于时间的唯一ID
|
||||||
|
/// 格式:时间戳_UUID,保证唯一性和可读性
|
||||||
|
static String generateTimeBasedId() {
|
||||||
|
final timestamp = DateTime.now().millisecondsSinceEpoch;
|
||||||
|
final shortUuid = generateShortId();
|
||||||
|
return '${timestamp}_$shortUuid';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 生成图片文件的唯一文件名
|
||||||
|
/// [extension] 文件扩展名(包含点号,如 .jpg)
|
||||||
|
/// [prefix] 可选前缀,如 "IMG_"
|
||||||
|
static String generateImageFileName({
|
||||||
|
required String extension,
|
||||||
|
String? prefix,
|
||||||
|
}) {
|
||||||
|
final baseName = generateTimeBasedId();
|
||||||
|
final fileName = prefix != null ? '${prefix}$baseName' : baseName;
|
||||||
|
return '$fileName$extension';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 生成缩略图文件名
|
||||||
|
/// 在原文件名基础上添加 _thumb 后缀
|
||||||
|
static String generateThumbnailFileName(String originalFileName) {
|
||||||
|
final nameWithoutExt = path.basenameWithoutExtension(originalFileName);
|
||||||
|
final extension = path.extension(originalFileName);
|
||||||
|
return '${nameWithoutExt}_thumb$extension';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 构建日期分类的存储路径
|
||||||
|
/// 按照 /yyyy/MM/dd/ 格式组织
|
||||||
|
/// [basePath] 基础路径
|
||||||
|
/// [date] 日期,默认为当前时间
|
||||||
|
static String buildDateBasedPath({
|
||||||
|
required String basePath,
|
||||||
|
DateTime? date,
|
||||||
|
}) {
|
||||||
|
final targetDate = date ?? DateTime.now();
|
||||||
|
final year = targetDate.year.toString();
|
||||||
|
final month = targetDate.month.toString().padLeft(2, '0');
|
||||||
|
final day = targetDate.day.toString().padLeft(2, '0');
|
||||||
|
|
||||||
|
return path.join(basePath, year, month, day);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 构建图片存储路径
|
||||||
|
/// 返回完整的图片存储路径,包含日期分类
|
||||||
|
static Future<String> buildImageStoragePath({
|
||||||
|
required String fileName,
|
||||||
|
DateTime? date,
|
||||||
|
}) async {
|
||||||
|
try {
|
||||||
|
final supportDir = await path_provider.getApplicationSupportDirectory();
|
||||||
|
final imagesBasePath = path.join(supportDir.path, 'images');
|
||||||
|
final dateBasedPath = buildDateBasedPath(
|
||||||
|
basePath: imagesBasePath,
|
||||||
|
date: date,
|
||||||
|
);
|
||||||
|
|
||||||
|
return path.join(dateBasedPath, fileName);
|
||||||
|
} catch (error, stackTrace) {
|
||||||
|
Logger.error('构建图片存储路径失败', error: error, stackTrace: stackTrace);
|
||||||
|
throw StorageError(
|
||||||
|
message: '构建图片存储路径失败: ${error.toString()}',
|
||||||
|
code: 'PATH_ERROR',
|
||||||
|
stackTrace: stackTrace,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 构建缩略图存储路径
|
||||||
|
/// 返回完整的缩略图存储路径,包含日期分类
|
||||||
|
static Future<String> buildThumbnailStoragePath({
|
||||||
|
required String fileName,
|
||||||
|
DateTime? date,
|
||||||
|
}) async {
|
||||||
|
try {
|
||||||
|
final supportDir = await path_provider.getApplicationSupportDirectory();
|
||||||
|
final thumbnailsBasePath = path.join(supportDir.path, 'thumbnails');
|
||||||
|
final dateBasedPath = buildDateBasedPath(
|
||||||
|
basePath: thumbnailsBasePath,
|
||||||
|
date: date,
|
||||||
|
);
|
||||||
|
|
||||||
|
return path.join(dateBasedPath, fileName);
|
||||||
|
} catch (error, stackTrace) {
|
||||||
|
Logger.error('构建缩略图存储路径失败', error: error, stackTrace: stackTrace);
|
||||||
|
throw StorageError(
|
||||||
|
message: '构建缩略图存储路径失败: ${error.toString()}',
|
||||||
|
code: 'PATH_ERROR',
|
||||||
|
stackTrace: stackTrace,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 获取文件的相对路径
|
||||||
|
/// 相对于应用支持目录的路径
|
||||||
|
static Future<String> getRelativePath(String fullPath) async {
|
||||||
|
try {
|
||||||
|
final supportDir = await path_provider.getApplicationSupportDirectory();
|
||||||
|
return path.relative(fullPath, from: supportDir.path);
|
||||||
|
} catch (error, stackTrace) {
|
||||||
|
Logger.error('获取相对路径失败', error: error, stackTrace: stackTrace);
|
||||||
|
throw StorageError(
|
||||||
|
message: '获取相对路径失败: ${error.toString()}',
|
||||||
|
code: 'PATH_ERROR',
|
||||||
|
stackTrace: stackTrace,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 从相对路径获取完整路径
|
||||||
|
static Future<String> getFullPath(String relativePath) async {
|
||||||
|
try {
|
||||||
|
final supportDir = await path_provider.getApplicationSupportDirectory();
|
||||||
|
return path.normalize(path.join(supportDir.path, relativePath));
|
||||||
|
} catch (error, stackTrace) {
|
||||||
|
Logger.error('获取完整路径失败', error: error, stackTrace: stackTrace);
|
||||||
|
throw StorageError(
|
||||||
|
message: '获取完整路径失败: ${error.toString()}',
|
||||||
|
code: 'PATH_ERROR',
|
||||||
|
stackTrace: stackTrace,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 检查路径是否安全
|
||||||
|
/// 防止路径遍历攻击
|
||||||
|
static bool isPathSafe(String pathToCheck) {
|
||||||
|
try {
|
||||||
|
// 检查是否包含路径遍历字符
|
||||||
|
if (pathToCheck.contains('..') || pathToCheck.contains('~')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否为绝对路径
|
||||||
|
if (path.isAbsolute(pathToCheck)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查路径是否规范化
|
||||||
|
final normalizedPath = path.normalize(pathToCheck);
|
||||||
|
return normalizedPath == pathToCheck;
|
||||||
|
} catch (error) {
|
||||||
|
Logger.error('路径安全检查失败', error: error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 获取路径的父目录
|
||||||
|
static String getParentDirectory(String filePath) {
|
||||||
|
return path.dirname(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 检查文件扩展名是否有效
|
||||||
|
static bool isValidFileExtension(String fileName, List<String> validExtensions) {
|
||||||
|
final extension = path.extension(fileName).toLowerCase();
|
||||||
|
return validExtensions.map((ext) => ext.toLowerCase()).contains(extension);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 生成备份文件名
|
||||||
|
/// 在原文件名基础上添加备份时间戳
|
||||||
|
static String generateBackupFileName(String originalFileName) {
|
||||||
|
final nameWithoutExt = path.basenameWithoutExtension(originalFileName);
|
||||||
|
final extension = path.extension(originalFileName);
|
||||||
|
final timestamp = DateTime.now().millisecondsSinceEpoch;
|
||||||
|
return '${nameWithoutExt}_backup_$timestamp$extension';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 生成临时文件名
|
||||||
|
/// 用于临时文件操作,格式:temp_UUID.扩展名
|
||||||
|
static String generateTempFileName(String extension) {
|
||||||
|
final uuid = generateShortId();
|
||||||
|
return 'temp_$uuid$extension';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 解析日期分类路径
|
||||||
|
/// 从 /yyyy/MM/dd/ 格式的路径中提取日期信息
|
||||||
|
static DateTime? parseDateFromPath(String dateBasedPath) {
|
||||||
|
try {
|
||||||
|
// 标准化路径分隔符
|
||||||
|
final normalizedPath = path.normalize(dateBasedPath);
|
||||||
|
final pathParts = normalizedPath.split(path.separator);
|
||||||
|
|
||||||
|
// 查找年、月、日的位置
|
||||||
|
int yearIndex = -1, monthIndex = -1, dayIndex = -1;
|
||||||
|
|
||||||
|
for (int i = 0; i < pathParts.length; i++) {
|
||||||
|
final part = pathParts[i];
|
||||||
|
if (part.length == 4 && int.tryParse(part) != null && int.parse(part) > 1900 && int.parse(part) < 3000) {
|
||||||
|
yearIndex = i;
|
||||||
|
} else if (part.length == 2 && int.tryParse(part) != null && int.parse(part) >= 1 && int.parse(part) <= 12) {
|
||||||
|
if (monthIndex == -1) {
|
||||||
|
monthIndex = i;
|
||||||
|
} else if (dayIndex == -1) {
|
||||||
|
dayIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (yearIndex != -1 && monthIndex != -1 && dayIndex != -1) {
|
||||||
|
final year = int.parse(pathParts[yearIndex]);
|
||||||
|
final month = int.parse(pathParts[monthIndex]);
|
||||||
|
final day = int.parse(pathParts[dayIndex]);
|
||||||
|
|
||||||
|
return DateTime(year, month, day);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
} catch (error) {
|
||||||
|
Logger.error('解析日期路径失败', error: error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 获取路径的层级深度
|
||||||
|
static int getPathDepth(String pathToCheck) {
|
||||||
|
return path.split(path.normalize(pathToCheck)).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 检查两个路径是否有相同的父目录
|
||||||
|
static bool hasSameParentDirectory(String path1, String path2) {
|
||||||
|
final parent1 = path.dirname(path.normalize(path1));
|
||||||
|
final parent2 = path.dirname(path.normalize(path2));
|
||||||
|
return parent1 == parent2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 生成安全的文件名
|
||||||
|
/// 移除不安全的字符,确保文件名有效
|
||||||
|
static String sanitizeFileName(String fileName) {
|
||||||
|
// 移除或替换不安全的字符
|
||||||
|
final sanitized = fileName
|
||||||
|
.replaceAll(RegExp(r'[<>:"/\\|?*]'), '_')
|
||||||
|
.replaceAll(RegExp(r'\s+'), '_')
|
||||||
|
.replaceAll(RegExp(r'_{2,}'), '_')
|
||||||
|
.trim();
|
||||||
|
|
||||||
|
// 确保文件名不为空
|
||||||
|
if (sanitized.isEmpty) {
|
||||||
|
return 'unnamed_file';
|
||||||
|
}
|
||||||
|
|
||||||
|
return sanitized;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 路径构建器类
|
||||||
|
/// 提供链式调用的路径构建方式
|
||||||
|
class PathBuilder {
|
||||||
|
final String _basePath;
|
||||||
|
final List<String> _segments;
|
||||||
|
|
||||||
|
PathBuilder(this._basePath) : _segments = [];
|
||||||
|
|
||||||
|
/// 添加路径段
|
||||||
|
PathBuilder add(String segment) {
|
||||||
|
_segments.add(segment);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 添加日期段
|
||||||
|
PathBuilder addDate(DateTime date) {
|
||||||
|
final year = date.year.toString();
|
||||||
|
final month = date.month.toString().padLeft(2, '0');
|
||||||
|
final day = date.day.toString().padLeft(2, '0');
|
||||||
|
|
||||||
|
_segments.addAll([year, month, day]);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 添加UUID段
|
||||||
|
PathBuilder addUuid() {
|
||||||
|
_segments.add(PathUtils.generateShortId());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 构建完整路径
|
||||||
|
String build() {
|
||||||
|
if (_segments.isEmpty) {
|
||||||
|
return _basePath;
|
||||||
|
}
|
||||||
|
return path.join(_basePath, _segments.join(path.separator));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 创建目录
|
||||||
|
Future<Directory> createDirectory() async {
|
||||||
|
final fullPath = build();
|
||||||
|
final directory = Directory(fullPath);
|
||||||
|
|
||||||
|
if (!await directory.exists()) {
|
||||||
|
await directory.create(recursive: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return directory;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,6 +2,7 @@ import 'package:hive/hive.dart';
|
|||||||
import '../../models/hive_inspiration_image.dart';
|
import '../../models/hive_inspiration_image.dart';
|
||||||
import '../../models/hive_image_folder.dart';
|
import '../../models/hive_image_folder.dart';
|
||||||
import '../../models/hive_image_tag.dart';
|
import '../../models/hive_image_tag.dart';
|
||||||
|
import '../../../core/utils/logger.dart';
|
||||||
|
|
||||||
/// 数据库迁移管理类 - 负责处理数据库版本升级和数据迁移
|
/// 数据库迁移管理类 - 负责处理数据库版本升级和数据迁移
|
||||||
/// 确保应用在升级时能够正确迁移旧版本数据
|
/// 确保应用在升级时能够正确迁移旧版本数据
|
||||||
@ -120,8 +121,7 @@ class DatabaseMigration {
|
|||||||
|
|
||||||
await foldersBox.put(folder.id, folder);
|
await foldersBox.put(folder.id, folder);
|
||||||
} else {
|
} else {
|
||||||
// TODO: 使用日志系统替代print
|
Logger.debug('默认文件夹已存在: ${folderConfig['name']}');
|
||||||
// print('默认文件夹已存在: ${folderConfig['name']}');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -129,7 +129,7 @@ class DatabaseMigration {
|
|||||||
/// 创建默认标签 - 初始化系统常用的标签
|
/// 创建默认标签 - 初始化系统常用的标签
|
||||||
/// [tagsBox] 标签数据盒
|
/// [tagsBox] 标签数据盒
|
||||||
static Future<void> createDefaultTags(Box<HiveImageTag> tagsBox) async {
|
static Future<void> createDefaultTags(Box<HiveImageTag> tagsBox) async {
|
||||||
print('创建默认标签...');
|
Logger.info('创建默认标签...');
|
||||||
|
|
||||||
// 默认标签配置
|
// 默认标签配置
|
||||||
final defaultTags = [
|
final defaultTags = [
|
||||||
@ -219,8 +219,7 @@ class DatabaseMigration {
|
|||||||
Box<HiveImageFolder> foldersBox,
|
Box<HiveImageFolder> foldersBox,
|
||||||
Box<HiveImageTag> tagsBox,
|
Box<HiveImageTag> tagsBox,
|
||||||
) async {
|
) async {
|
||||||
// TODO: 使用日志系统替代print
|
Logger.info('开始数据库完整性验证...');
|
||||||
// print('开始数据库完整性验证...');
|
|
||||||
|
|
||||||
bool isValid = true;
|
bool isValid = true;
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import 'package:path_provider/path_provider.dart' as path_provider;
|
|||||||
import '../../../data/models/hive_inspiration_image.dart';
|
import '../../../data/models/hive_inspiration_image.dart';
|
||||||
import '../../../data/models/hive_image_folder.dart';
|
import '../../../data/models/hive_image_folder.dart';
|
||||||
import '../../../data/models/hive_image_tag.dart';
|
import '../../../data/models/hive_image_tag.dart';
|
||||||
|
import '../../../core/utils/logger.dart';
|
||||||
import 'database_migration.dart';
|
import 'database_migration.dart';
|
||||||
|
|
||||||
/// Hive数据库管理类 - 负责本地数据存储和初始化
|
/// Hive数据库管理类 - 负责本地数据存储和初始化
|
||||||
@ -65,7 +66,7 @@ class HiveDatabase {
|
|||||||
|
|
||||||
if (currentDbVersion < _currentVersion) {
|
if (currentDbVersion < _currentVersion) {
|
||||||
try {
|
try {
|
||||||
print('检测到数据库版本更新: $currentDbVersion -> $_currentVersion');
|
Logger.info('检测到数据库版本更新: $currentDbVersion -> $_currentVersion');
|
||||||
|
|
||||||
// 使用专门的迁移管理类执行迁移
|
// 使用专门的迁移管理类执行迁移
|
||||||
await DatabaseMigration.migrateFromVersion(
|
await DatabaseMigration.migrateFromVersion(
|
||||||
@ -76,15 +77,15 @@ class HiveDatabase {
|
|||||||
settingsBox,
|
settingsBox,
|
||||||
);
|
);
|
||||||
|
|
||||||
print('数据库迁移完成');
|
Logger.info('数据库迁移完成');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('数据库迁移失败: $e');
|
Logger.error('数据库迁移失败', error: e);
|
||||||
// 如果迁移失败,尝试恢复到已知状态
|
// 如果迁移失败,尝试恢复到已知状态
|
||||||
await _handleMigrationFailure(currentDbVersion, e);
|
await _handleMigrationFailure(currentDbVersion, e);
|
||||||
}
|
}
|
||||||
} else if (currentDbVersion > _currentVersion) {
|
} else if (currentDbVersion > _currentVersion) {
|
||||||
// 处理降级情况(通常不应该发生)
|
// 处理降级情况(通常不应该发生)
|
||||||
print('警告:数据库版本高于应用版本 ($currentDbVersion > $_currentVersion)');
|
Logger.warning('数据库版本高于应用版本 ($currentDbVersion > $_currentVersion)');
|
||||||
await settingsBox.put(_versionKey, _currentVersion);
|
await settingsBox.put(_versionKey, _currentVersion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -93,7 +94,7 @@ class HiveDatabase {
|
|||||||
/// [fromVersion] 迁移起始版本
|
/// [fromVersion] 迁移起始版本
|
||||||
/// [error] 迁移过程中出现的错误
|
/// [error] 迁移过程中出现的错误
|
||||||
static Future<void> _handleMigrationFailure(int fromVersion, dynamic error) async {
|
static Future<void> _handleMigrationFailure(int fromVersion, dynamic error) async {
|
||||||
print('处理迁移失败,尝试恢复到安全状态...');
|
Logger.error('处理迁移失败,尝试恢复到安全状态...', error: error);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 如果是最初版本(0)的迁移失败,可以尝试重新创建基础结构
|
// 如果是最初版本(0)的迁移失败,可以尝试重新创建基础结构
|
||||||
@ -107,7 +108,7 @@ class HiveDatabase {
|
|||||||
await settingsBox.put('last_migration_time', DateTime.now().toIso8601String());
|
await settingsBox.put('last_migration_time', DateTime.now().toIso8601String());
|
||||||
|
|
||||||
} catch (recoveryError) {
|
} catch (recoveryError) {
|
||||||
print('迁移恢复失败: $recoveryError');
|
Logger.fatal('迁移恢复失败', error: recoveryError);
|
||||||
// 如果恢复也失败,只能抛出异常让上层处理
|
// 如果恢复也失败,只能抛出异常让上层处理
|
||||||
throw DatabaseMigrationException(
|
throw DatabaseMigrationException(
|
||||||
fromVersion: fromVersion,
|
fromVersion: fromVersion,
|
||||||
@ -132,7 +133,7 @@ class HiveDatabase {
|
|||||||
/// 创建紧急恢复数据 - 当迁移失败时的紧急恢复方案
|
/// 创建紧急恢复数据 - 当迁移失败时的紧急恢复方案
|
||||||
/// 确保应用至少能正常运行,包含最基本的数据结构
|
/// 确保应用至少能正常运行,包含最基本的数据结构
|
||||||
static Future<void> _createEmergencyData() async {
|
static Future<void> _createEmergencyData() async {
|
||||||
print('创建紧急恢复数据...');
|
Logger.warning('创建紧急恢复数据...');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final foldersBox = Hive.box<HiveImageFolder>(_foldersBoxName);
|
final foldersBox = Hive.box<HiveImageFolder>(_foldersBoxName);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user