BackupService.cs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. using Serilog;
  2. namespace YZWater.Core.Services;
  3. /// <summary>
  4. /// 数据库备份服务
  5. /// </summary>
  6. public static class BackupService
  7. {
  8. private static readonly string BackupDir = "Backups";
  9. /// <summary>
  10. /// 创建数据库备份
  11. /// </summary>
  12. public static async Task<(bool Success, string Path)> BackupAsync()
  13. {
  14. try
  15. {
  16. Directory.CreateDirectory(BackupDir);
  17. var timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
  18. var backupPath = Path.Combine(BackupDir, $"yzwater_backup_{timestamp}.db");
  19. // SQLite 备份:复制数据库文件
  20. var sourcePath = "yzwater.db";
  21. if (!File.Exists(sourcePath))
  22. {
  23. Log.Warning("数据库文件不存在: {Path}", sourcePath);
  24. return (false, string.Empty);
  25. }
  26. // 使用 SqlSugar 的备份功能
  27. var db = DatabaseService.Db;
  28. await Task.Run(() =>
  29. {
  30. File.Copy(sourcePath, backupPath, true);
  31. });
  32. Log.Information("数据库备份成功: {Path}", backupPath);
  33. AuditService.Log("系统", "Backup", $"数据库备份: {backupPath}");
  34. return (true, backupPath);
  35. }
  36. catch (Exception ex)
  37. {
  38. Log.Error(ex, "数据库备份失败");
  39. return (false, string.Empty);
  40. }
  41. }
  42. /// <summary>
  43. /// 恢复数据库
  44. /// </summary>
  45. public static async Task<bool> RestoreAsync(string backupPath)
  46. {
  47. try
  48. {
  49. if (!File.Exists(backupPath))
  50. {
  51. Log.Warning("备份文件不存在: {Path}", backupPath);
  52. return false;
  53. }
  54. var targetPath = "yzwater.db";
  55. // 先备份当前数据库
  56. var preRestoreBackup = Path.Combine(BackupDir, $"yzwater_pre_restore_{DateTime.Now:yyyyMMdd_HHmmss}.db");
  57. if (File.Exists(targetPath))
  58. {
  59. File.Copy(targetPath, preRestoreBackup, true);
  60. }
  61. await Task.Run(() =>
  62. {
  63. File.Copy(backupPath, targetPath, true);
  64. });
  65. Log.Information("数据库恢复成功,恢复前备份: {Path}", preRestoreBackup);
  66. AuditService.Log("系统", "Restore", $"数据库恢复: {backupPath},恢复前备份: {preRestoreBackup}");
  67. return true;
  68. }
  69. catch (Exception ex)
  70. {
  71. Log.Error(ex, "数据库恢复失败");
  72. return false;
  73. }
  74. }
  75. /// <summary>
  76. /// 获取备份列表
  77. /// </summary>
  78. public static List<(string Path, DateTime Time, long Size)> GetBackups()
  79. {
  80. if (!Directory.Exists(BackupDir))
  81. return new List<(string, DateTime, long)>();
  82. return Directory.GetFiles(BackupDir, "*.db")
  83. .Select(f => new FileInfo(f))
  84. .OrderByDescending(f => f.CreationTime)
  85. .Select(f => (f.FullName, f.CreationTime, f.Length))
  86. .ToList();
  87. }
  88. /// <summary>
  89. /// 清理旧备份(保留最近 N 个)
  90. /// </summary>
  91. public static int CleanupOldBackups(int keepCount = 10)
  92. {
  93. if (!Directory.Exists(BackupDir))
  94. return 0;
  95. var backups = Directory.GetFiles(BackupDir, "*.db")
  96. .Select(f => new FileInfo(f))
  97. .OrderByDescending(f => f.CreationTime)
  98. .Skip(keepCount)
  99. .ToList();
  100. foreach (var backup in backups)
  101. {
  102. try
  103. {
  104. backup.Delete();
  105. Log.Debug("已删除旧备份: {Path}", backup.FullName);
  106. }
  107. catch (Exception ex)
  108. {
  109. Log.Warning(ex, "删除旧备份失败: {Path}", backup.FullName);
  110. }
  111. }
  112. if (backups.Count > 0)
  113. Log.Information("已清理 {Count} 个旧备份", backups.Count);
  114. return backups.Count;
  115. }
  116. }