Files
biz_xfj_cloud/lib/common/utils/app/app_file_tool.dart
T

229 lines
7.8 KiB
Dart

import 'dart:io';
import 'package:common_utils/common_utils.dart';
import 'package:external_path/external_path.dart';
import 'package:pj_supermarket_cloud/common/index.dart';
import 'package:sqflite/sqflite.dart';
abstract class AppFileTool {
static const _tag = "app文件工具";
static const _baseDir = "pj_cashier";
static const _baseBackupDir = "backup";
static const _backupDatabaseDir = "database";
static const _backupLoggerDir = "logger";
static const _backupFaceDir = "face";
/// 检查并创建目录
static Future<String> _checkAndcreateDir(String dir) async {
Directory targetDir = Directory(dir);
if (!await targetDir.exists()) {
await targetDir.create(recursive: true);
}
return dir;
}
/// 获取外部路径
static Future<String> getExternalPath({
bool backupExternalPath = true,
}) async {
final documentsDir = await ExternalPath.getExternalStoragePublicDirectory(
ExternalPath.DIRECTORY_DOCUMENTS,
);
final backupDir = "$documentsDir/$_baseDir";
if (backupExternalPath) {
final sysSetting = await AppSettingTool.getSysSetting();
sysSetting.externalPath = documentsDir;
await AppSettingTool.setSysSetting(sysSetting);
}
return backupDir;
}
/// 创建数据库文件地址
static Future<String?> getDatabasePath() async {
String backupDir = await getExternalPath(backupExternalPath: false);
String dir = "$backupDir/$_backupDatabaseDir";
dir = await _checkAndcreateDir(dir);
return dir;
}
/// 创建数据库文件备份地址
static Future<String?> getDatabaseBackupPath() async {
String backupDir = await getExternalPath(backupExternalPath: false);
String dir = "$backupDir/$_baseBackupDir/$_backupDatabaseDir";
DateTime now = DateTime.now();
int year = now.year;
int month = now.month;
int day = now.day;
dir = "$dir/$year-$month";
dir = await _checkAndcreateDir(dir);
dir = "$dir/$day.db";
return dir;
}
/// 创建日志地址
static Future<String?> getLoggerPath() async {
final backupDir = await getExternalPath();
return _checkAndcreateDir("$backupDir/$_backupLoggerDir");
}
/// 创建日志备份地址
static Future<String?> getLoggerBackupPath() async {
final backupDir = await getExternalPath(backupExternalPath: false);
String dir = "$backupDir/$_baseBackupDir/$_backupLoggerDir";
DateTime now = DateTime.now();
int year = now.year;
int month = now.month;
int day = now.day;
dir = "$dir/$year-$month";
dir = await _checkAndcreateDir(dir);
dir = "$dir/$day.log";
return dir;
}
/// 创建一次性日志快照地址,避免手动导出覆盖当前仍在写入的实时日志文件。
static Future<String?> getLoggerSnapshotPath() async {
final backupDir = await getExternalPath(backupExternalPath: false);
String dir = "$backupDir/$_baseBackupDir/$_backupLoggerDir/manual";
dir = await _checkAndcreateDir(dir);
final now = DateTime.now();
final stamp = now.toIso8601String().replaceAll(':', '-');
return "$dir/log-$stamp.log";
}
/// 创建人脸地址
static Future<String?> getFacePath() async {
final backupDir = await getExternalPath();
return _checkAndcreateDir("$backupDir/$_backupFaceDir");
}
/// 创建人脸备份地址
static Future<String?> getFaceBackupPath() async {
final backupDir = await getExternalPath();
return _checkAndcreateDir("$backupDir/$_baseBackupDir/$_backupFaceDir");
}
/// 备份数据库并返回生成文件,页面据此展示真实结果和最近备份时间。
static Future<String?> backupSqlFilePath() async {
final sourcePath = await getDatabasePath();
if (ObjectUtil.isEmpty(sourcePath)) {
logger.e("|$_tag|备份sql文件失败,无效的sourcePath路径path:|$sourcePath|");
return null;
}
final databaseFilePath = "$sourcePath/${Constants.databaseName}";
if (!await File(databaseFilePath).exists()) {
logger.w("|$_tag|备份sql文件失败,无效的sourcePath路径path|$databaseFilePath|");
return null;
}
String? backupPath = await getDatabaseBackupPath();
if (ObjectUtil.isEmpty(backupPath)) {
logger.e("|$_tag|备份sql文件失败,无效的backupPath路径path:|$backupPath|");
return null;
}
try {
await File(databaseFilePath).copy(backupPath!);
return backupPath;
} catch (e, stack) {
logger.e("|$_tag|备份sql文件失败,意外的错误error|$e|stack|$stack|");
return null;
}
}
// 保留旧接口,应用启动时仍可按原方式进行自动备份。
static Future<bool> backupSqlFile() async {
return await backupSqlFilePath() != null;
}
/// 将当前实时日志复制为独立快照,不中断 Logger 正在持有的文件句柄。
static Future<String?> backupLogFile() async {
final sourcePath = await getLoggerBackupPath();
final targetPath = await getLoggerSnapshotPath();
if (ObjectUtil.isEmpty(sourcePath) || ObjectUtil.isEmpty(targetPath)) {
return null;
}
final source = File(sourcePath!);
if (!await source.exists()) {
logger.w("|$_tag|备份日志失败,实时日志不存在path|$sourcePath|");
return null;
}
try {
await source.copy(targetPath!);
return targetPath;
} catch (e, stack) {
logger.e("|$_tag|备份日志失败error|$e|stack|$stack|");
return null;
}
}
/// 获取目录中最近生成文件的修改时间。
static Future<DateTime?> getLatestModifiedTime(String? path) async {
if (ObjectUtil.isEmpty(path)) return null;
final entity = FileSystemEntity.typeSync(path!);
if (entity == FileSystemEntityType.file) {
return File(path).stat().then((value) => value.modified);
}
final directory = Directory(path);
if (!await directory.exists()) return null;
DateTime? latest;
await for (final file in directory.list(recursive: true)) {
if (file is! File) continue;
final modified = (await file.stat()).modified;
if (latest == null || modified.isAfter(latest)) latest = modified;
}
return latest;
}
// 如果没有数据库将最新的数据库移动为使用的数据库
static Future<void> useLastBackDatabase() async {
final databasePath = getDatabasesPath();
final databaseFilePath = "$databasePath/${Constants.databaseName}";
if (await File(databaseFilePath).exists()) {
logger.w("|$_tag|替换数据库错误,数据库文件已存在path|$databaseFilePath|");
return;
}
final path = await getDatabaseBackupPath();
if (ObjectUtil.isEmpty(path)) {
logger.w("|$_tag|替换数据库错误,无效的数据库备份path|$path|");
return;
}
final dir = Directory(path!).parent;
if (!await dir.exists()) {
logger.w("|$_tag|替换数据库错误,无效的数据库备份目录path|$dir|");
return;
}
final files = dir.listSync();
files.sort(
(a, b) => b.statSync().modified.compareTo(a.statSync().modified),
);
if (files.isEmpty) {
logger.w("|$_tag|替换数据库错误,数据库备份目录为空path|$dir|");
return;
}
final lastFile = files.first;
try {
if (lastFile is File) {
final sourcePath = lastFile.path;
await File(sourcePath).copy(databaseFilePath);
logger.i(
"|$_tag|替换数据库成功,sourcePath|$sourcePath|targetPath|$databaseFilePath|",
);
}
} catch (e, stack) {
logger.e("|$_tag|替换数据库错误,意外的错误error|$e|stack|$stack|");
}
}
// 获取文件后缀
static String getFileExtension(String url) {
int lastDotIndex = url.lastIndexOf('.');
if (lastDotIndex == -1) {
return '';
}
int lastSlashIndex = url.lastIndexOf('/');
if (lastDotIndex > lastSlashIndex) {
return url.substring(lastDotIndex);
}
return '';
}
}