2025-11-14
C#
00

目录

为什么需要SQLite备份恢复服务?
核心功能设计
完整实现代码
使用示例
高级功能实现
备份文件加密保护
备份文件压缩
备份到远程存储
总结

【导读】数据安全是应用开发的重中之重,一套可靠的备份恢复机制是确保数据安全的基础保障。本文详细讲解如何使用C#开发SQLite数据库备份与恢复服务,提供完整代码示例与最佳实践,助您构建更稳固的应用程序。

为什么需要SQLite备份恢复服务?

在开发使用SQLite的应用时,无论是桌面应用、小型Web服务还是移动应用,数据库备份与恢复功能都至关重要:

  • 防范数据丢失风险:系统崩溃、误操作或硬件故障时恢复数据
  • 支持系统迁移部署:轻松将数据库迁移到新环境
  • 实现版本回滚能力:出现问题时快速恢复到稳定版本
  • 提升应用可靠性:建立用户对应用的信任
  • 满足合规性要求:某些行业要求定期备份数据

核心功能设计

一个完善的SQLite备份恢复服务应包含以下关键功能:

  1. 定期自动备份:按设定间隔执行自动备份
  2. 手动备份触发:支持用户随时创建备份点
  3. 备份文件管理:控制备份数量和占用空间
  4. 数据库恢复机制:从任意备份点恢复系统
  5. 日志与异常处理:记录备份恢复过程中的关键事件

完整实现代码

以下是一个功能完整的SQLite备份恢复服务实现,使用了标准的文件操作方法而非内部API:

C#
using System; using System.Collections.Generic; using System.Data.SQLite; using System.Linq; using System.Text; using System.Threading.Tasks; namespace AppBackup { using System; using System.IO; using System.Data.SQLite; using System.Collections.Generic; using System.Threading.Tasks; /// <summary> /// SQLite数据库备份和恢复服务 /// </summary> public class SqliteBackupService { // 数据库连接字符串 private readonly string _connectionString; // 数据库文件路径 private readonly string _databasePath; // 备份根目录 private readonly string _backupDirectory; // 备份保留策略(最大备份文件数) private const int MAX_BACKUP_FILES = 10; /// <summary> /// 构造函数 /// </summary> /// <param name="dbPath">数据库文件路径</param> /// <param name="backupDirectory">备份目录</param> public SqliteBackupService(string dbPath, string backupDirectory) { _databasePath = dbPath; _connectionString = $"Data Source={dbPath};Version=3;"; _backupDirectory = backupDirectory; // 确保备份目录存在 Directory.CreateDirectory(_backupDirectory); } /// <summary> /// 执行手动备份 /// </summary> /// <returns>备份文件路径</returns> public string ManualBackup() { try { // 首先确保关闭所有数据库连接 using (var connection = new SQLiteConnection(_connectionString)) { connection.Open(); // 执行VACUUM以优化数据库 using (var cmd = new SQLiteCommand("VACUUM", connection)) { cmd.ExecuteNonQuery(); } // 确保事务已提交 using (var cmd = new SQLiteCommand("PRAGMA wal_checkpoint(FULL)", connection)) { cmd.ExecuteNonQuery(); } connection.Close(); } // 生成备份文件名(包含时间戳) string backupFileName = $"backup_{DateTime.Now:yyyyMMdd_HHmmss}.db"; string backupPath = Path.Combine(_backupDirectory, backupFileName); // 直接复制数据库文件 File.Copy(_databasePath, backupPath, true); // 如果存在WAL文件,也一并备份 string walPath = _databasePath + "-wal"; if (File.Exists(walPath)) { string walBackupPath = backupPath + "-wal"; File.Copy(walPath, walBackupPath, true); } // 如果存在SHM文件,也一并备份 string shmPath = _databasePath + "-shm"; if (File.Exists(shmPath)) { string shmBackupPath = backupPath + "-shm"; File.Copy(shmPath, shmBackupPath, true); } // 管理备份文件数量 ManageBackupFiles(); LogInfo($"手动备份完成: {backupPath}"); return backupPath; } catch (Exception ex) { // 记录错误日志 LogError($"备份失败:{ex.Message}"); throw; } } /// <summary> /// 定期自动备份(异步方法) /// </summary> /// <returns>异步任务</returns> public async Task ScheduledBackupAsync() { try { // 在后台线程执行备份 await Task.Run(() => { ManualBackup(); }); } catch (Exception ex) { LogError($"定时备份失败:{ex.Message}"); } } /// <summary> /// 数据库恢复 /// </summary> /// <param name="backupFilePath">备份文件路径</param> public void RestoreDatabase(string backupFilePath) { try { // 验证备份文件是否存在 if (!File.Exists(backupFilePath)) { throw new FileNotFoundException("备份文件不存在"); } // 关闭所有数据库连接 GC.Collect(); GC.WaitForPendingFinalizers(); // 先创建一个当前数据库的备份,以防恢复失败 string tempBackupPath = Path.Combine( Path.GetDirectoryName(_databasePath), $"restore_backup_{DateTime.Now:yyyyMMdd_HHmmss}.db" ); File.Copy(_databasePath, tempBackupPath, true); try { // 替换当前数据库文件 File.Copy(backupFilePath, _databasePath, true); // 恢复WAL和SHM文件(如果存在) string walBackupPath = backupFilePath + "-wal"; if (File.Exists(walBackupPath)) { File.Copy(walBackupPath, _databasePath + "-wal", true); } string shmBackupPath = backupFilePath + "-shm"; if (File.Exists(shmBackupPath)) { File.Copy(shmBackupPath, _databasePath + "-shm", true); } LogInfo($"数据库已从 {backupFilePath} 恢复"); } catch (Exception ex) { // 恢复失败,还原原始数据库 File.Copy(tempBackupPath, _databasePath, true); LogError($"恢复失败,已还原原始数据库: {ex.Message}"); throw new Exception("数据库恢复失败,已自动回滚到原始状态", ex); } finally { // 清理临时备份 if (File.Exists(tempBackupPath)) { File.Delete(tempBackupPath); } } } catch (Exception ex) { LogError($"数据库恢复失败:{ex.Message}"); throw; } } /// <summary> /// 验证数据库备份的完整性 /// </summary> /// <param name="backupFilePath">备份文件路径</param> /// <returns>备份是否有效</returns> public bool ValidateBackup(string backupFilePath) { if (!File.Exists(backupFilePath)) { return false; } try { // 尝试打开备份数据库连接验证其完整性 using (var connection = new SQLiteConnection($"Data Source={backupFilePath};Version=3;")) { connection.Open(); // 执行简单查询测试 using (var cmd = new SQLiteCommand("PRAGMA integrity_check", connection)) { string result = cmd.ExecuteScalar()?.ToString(); return result == "ok"; } } } catch { return false; } } /// <summary> /// 管理备份文件数量 /// </summary> private void ManageBackupFiles() { try { // 获取所有备份文件 var backupFiles = Directory.GetFiles(_backupDirectory, "backup_*.db"); // 按创建时间排序 Array.Sort(backupFiles, (a, b) => File.GetCreationTime(a).CompareTo(File.GetCreationTime(b))); // 如果备份文件超过最大限制,删除最旧的备份 if (backupFiles.Length > MAX_BACKUP_FILES) { for (int i = 0; i < backupFiles.Length - MAX_BACKUP_FILES; i++) { File.Delete(backupFiles[i]); // 同时删除关联的WAL和SHM文件 string walFile = backupFiles[i] + "-wal"; if (File.Exists(walFile)) { File.Delete(walFile); } string shmFile = backupFiles[i] + "-shm"; if (File.Exists(shmFile)) { File.Delete(shmFile); } LogInfo($"已删除过期备份: {backupFiles[i]}"); } } } catch (Exception ex) { LogError($"备份文件管理失败:{ex.Message}"); } } /// <summary> /// 获取所有备份文件信息 /// </summary> /// <returns>备份文件信息列表</returns> public List<BackupInfo> GetBackupList() { var result = new List<BackupInfo>(); var backupFiles = Directory.GetFiles(_backupDirectory, "backup_*.db"); foreach (var file in backupFiles) { var fileInfo = new FileInfo(file); result.Add(new BackupInfo { FilePath = file, FileName = Path.GetFileName(file), CreationTime = fileInfo.CreationTime, Size = fileInfo.Length, IsValid = ValidateBackup(file) }); } // 按创建时间降序排序(最新的在前) result.Sort((a, b) => b.CreationTime.CompareTo(a.CreationTime)); return result; } /// <summary> /// 获取备份文件的详细信息 /// </summary> /// <param name="backupFilePath">备份文件路径</param> /// <returns>备份详细信息</returns> public BackupInfo GetBackupDetails(string backupFilePath) { if (!File.Exists(backupFilePath)) { return null; } var fileInfo = new FileInfo(backupFilePath); return new BackupInfo { FilePath = backupFilePath, FileName = Path.GetFileName(backupFilePath), CreationTime = fileInfo.CreationTime, Size = fileInfo.Length, IsValid = ValidateBackup(backupFilePath) }; } /// <summary> /// 日志信息记录 /// </summary> /// <param name="message">日志消息</param> private void LogInfo(string message) { // 实际项目中可替换为更完善的日志系统 Console.WriteLine($"[{DateTime.Now}] [INFO] {message}"); } /// <summary> /// 错误日志记录 /// </summary> /// <param name="errorMessage">错误消息</param> private void LogError(string errorMessage) { // 实际项目中可替换为更完善的日志系统 Console.Error.WriteLine($"[{DateTime.Now}] [ERROR] {errorMessage}"); } } /// <summary> /// 备份文件信息类 /// </summary> public class BackupInfo { /// <summary> /// 备份文件完整路径 /// </summary> public string FilePath { get; set; } /// <summary> /// 备份文件名 /// </summary> public string FileName { get; set; } /// <summary> /// 备份创建时间 /// </summary> public DateTime CreationTime { get; set; } /// <summary> /// 备份文件大小(字节) /// </summary> public long Size { get; set; } /// <summary> /// 备份是否有效 /// </summary> public bool IsValid { get; set; } } }

使用示例

下面是如何集成和使用上述备份恢复服务的示例代码:

C#
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace AppBackup { /// <summary> /// 备份服务使用示例 /// </summary> public class BackupServiceDemo { private readonly SqliteBackupService _backupService; private System.Timers.Timer _backupTimer; public BackupServiceDemo(string databasePath) { // 创建备份目录(相对于数据库文件) string backupDirectory = Path.Combine( Path.GetDirectoryName(databasePath), "backups" ); // 初始化备份服务 _backupService = new SqliteBackupService(databasePath, backupDirectory); // 设置定时备份(例如每6小时执行一次) SetupScheduledBackups(TimeSpan.FromHours(6)); } /// <summary> /// 设置定时备份 /// </summary> /// <param name="interval">备份时间间隔</param> public void SetupScheduledBackups(TimeSpan interval) { _backupTimer = new System.Timers.Timer(interval.TotalMilliseconds); _backupTimer.Elapsed += async (sender, e) => { await _backupService.ScheduledBackupAsync(); }; _backupTimer.Start(); Console.WriteLine($"已设置定时备份,间隔: {interval}"); } /// <summary> /// 手动触发备份 /// </summary> /// <returns>备份文件路径</returns> public string TriggerManualBackup() { Console.WriteLine("开始手动备份..."); return _backupService.ManualBackup(); } /// <summary> /// 展示所有可用备份 /// </summary> public void ShowAvailableBackups() { var backups = _backupService.GetBackupList(); Console.WriteLine("可用备份列表:"); Console.WriteLine("----------------------------------------"); foreach (var backup in backups) { string status = backup.IsValid ? "有效" : "无效"; double sizeInMB = Math.Round(backup.Size / 1024.0 / 1024.0, 2); Console.WriteLine($"文件名: {backup.FileName}"); Console.WriteLine($"创建时间: {backup.CreationTime}"); Console.WriteLine($"大小: {sizeInMB} MB"); Console.WriteLine($"状态: {status}"); Console.WriteLine("----------------------------------------"); } } /// <summary> /// 从指定备份恢复 /// </summary> /// <param name="backupFileName">备份文件名</param> public void RestoreFromBackup(string backupFileName) { var backups = _backupService.GetBackupList(); var selectedBackup = backups.FirstOrDefault(b => b.FileName == backupFileName); if (selectedBackup == null) { Console.WriteLine($"错误: 未找到备份文件 '{backupFileName}'"); return; } if (!selectedBackup.IsValid) { Console.WriteLine($"警告: 备份文件 '{backupFileName}' 可能已损坏,是否继续恢复? (y/n)"); string response = Console.ReadLine().ToLower(); if (response != "y") { Console.WriteLine("恢复操作已取消"); return; } } Console.WriteLine($"开始从备份 '{backupFileName}' 恢复数据库..."); _backupService.RestoreDatabase(selectedBackup.FilePath); Console.WriteLine("数据库恢复完成!"); } /// <summary> /// 停止备份服务 /// </summary> public void Shutdown() { _backupTimer?.Stop(); _backupTimer?.Dispose(); Console.WriteLine("备份服务已关闭"); } } }
C#
namespace AppBackup { internal class Program { static void Main(string[] args) { BackupServiceDemo backupServiceDemo = new BackupServiceDemo("D:\\myproject\\11Test\\AppSqlite\\example.db"); backupServiceDemo.TriggerManualBackup(); backupServiceDemo.ShowAvailableBackups(); backupServiceDemo.SetupScheduledBackups(TimeSpan.FromSeconds(5)); Console.ReadKey(); } } }

image.png

高级功能实现

备份文件加密保护

对于包含敏感数据的应用,建议实现备份文件加密:

备份文件压缩

对于大型数据库,添加压缩功能可以节省大量存储空间:

C#
/// <summary> /// 压缩备份文件 /// </summary> /// <param name="filePath">要压缩的文件路径</param> /// <returns>压缩后的文件路径</returns> public string CompressBackupFile(string filePath) { string compressedPath = filePath + ".gz"; using (var originalFile = File.OpenRead(filePath)) using (var compressedFile = File.Create(compressedPath)) using (var compressionStream = new System.IO.Compression.GZipStream( compressedFile, System.IO.Compression.CompressionMode.Compress)) { originalFile.CopyTo(compressionStream); } // 删除原始未压缩文件 File.Delete(filePath); return compressedPath; } /// <summary> /// 解压缩备份文件 /// </summary> /// <param name="compressedFilePath">压缩文件路径</param> /// <returns>解压后的文件路径</returns> public string DecompressBackupFile(string compressedFilePath) { if (!compressedFilePath.EndsWith(".gz")) { throw new ArgumentException("文件不是GZip压缩格式"); } string decompressedPath = compressedFilePath.Substring( 0, compressedFilePath.Length - 3); using (var compressedFile = File.OpenRead(compressedFilePath)) using (var decompressionStream = new System.IO.Compression.GZipStream( compressedFile, System.IO.Compression.CompressionMode.Decompress)) using (var decompressedFile = File.Create(decompressedPath)) { decompressionStream.CopyTo(decompressedFile); } return decompressedPath; }

备份到远程存储

为提高备份安全性,可以实现远程存储功能:

C#
/// <summary> /// 备份到FTP服务器 /// </summary> /// <param name="localFilePath">本地备份文件路径</param> /// <param name="ftpServer">FTP服务器地址</param> /// <param name="username">FTP用户名</param> /// <param name="password">FTP密码</param> /// <returns>上传是否成功</returns> public bool BackupToFtp(string localFilePath, string ftpServer, string username, string password) { try { string fileName = Path.GetFileName(localFilePath); string ftpPath = $"ftp://{ftpServer}/{fileName}"; // 创建FTP请求 var request = (FtpWebRequest)WebRequest.Create(ftpPath); request.Method = WebRequestMethods.Ftp.UploadFile; request.Credentials = new NetworkCredential(username, password); // 上传文件 byte[] fileBytes = File.ReadAllBytes(localFilePath); request.ContentLength = fileBytes.Length; using (var requestStream = request.GetRequestStream()) { requestStream.Write(fileBytes, 0, fileBytes.Length); } using (var response = (FtpWebResponse)request.GetResponse()) { LogInfo($"FTP上传完成,状态: {response.StatusDescription}"); } return true; } catch (Exception ex) { LogError($"FTP上传失败: {ex.Message}"); return false; } }

image.png

总结

本文详细介绍了使用C#开发SQLite数据库备份与恢复服务的完整解决方案。通过实现定期自动备份、手动备份触发、备份文件管理和数据库恢复等核心功能,可以有效保障应用数据的安全性。

此外,我们还探讨了备份加密、压缩和远程存储等高级特性,以及备份策略规划、安全保障和性能优化等最佳实践,帮助开发者构建一个全面而可靠的数据库备份系统。

对于任何依赖SQLite数据库的应用程序,实施本文所述的备份恢复服务将显著提高数据安全性和用户信任度,是专业应用开发不可或缺的重要组成部分。


关键词:C#、SQLite、数据库备份、数据恢复、数据安全、.NET开发、备份策略、数据保护、SQLite管理、数据库维护

本文是否对您有所帮助?欢迎关注我们的微信公众号,获取更多C#开发技巧和最佳实践!

相关信息

通过网盘分享的文件:AppSqliteBackup.zip 链接: https://pan.baidu.com/s/1t1t9Tqn8C_pBf9QaYCxxPg?pwd=6k42 提取码: 6k42 --来自百度网盘超级会员v9的分享

本文作者:技术老小子

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!