数据安全是应用开发的重中之重,一套可靠的备份恢复机制是确保数据安全的基础保障。本文详细讲解如何使用C#开发SQLite数据库备份与恢复服务,提供完整代码示例与最佳实践,助您构建更稳固的应用程序。
为什么需要SQLite备份恢复服务?
在开发使用SQLite的应用时,无论是桌面应用、小型Web服务还是移动应用,数据库备份与恢复功能都至关重要:
- 防范数据丢失风险
- 支持系统迁移部署
- 实现版本回滚能力
- 提升应用可靠性
- 满足合规性要求
核心功能设计
一个完善的SQLite备份恢复服务应包含以下关键功能:
- 定期自动备份
- 手动备份触发
- 备份文件管理
- 数据库恢复机制
- 日志与异常处理
完整实现代码
以下是一个功能完整的SQLite备份恢复服务实现,使用了标准的文件操作方法而非内部API:
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>
publicclass SqliteBackupService
{
// 数据库连接字符串
private readonly string _connectionString;
// 数据库文件路径
private readonly string _databasePath;
// 备份根目录
private readonly string _backupDirectory;
// 备份保留策略(最大备份文件数)
privateconstint 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))
{
thrownew 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}");
thrownew 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))
{
returnfalse;
}
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
{
returnfalse;
}
}
/// <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);
returnnew 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>
publicclass BackupInfo
{
/// <summary>
/// 备份文件完整路径
/// </summary>
publicstring FilePath { get; set; }
/// <summary>
/// 备份文件名
/// </summary>
publicstring FileName { get; set; }
/// <summary>
/// 备份创建时间
/// </summary>
public DateTime CreationTime { get; set; }
/// <summary>
/// 备份文件大小(字节)
/// </summary>
publiclong Size { get; set; }
/// <summary>
/// 备份是否有效
/// </summary>
publicbool IsValid { get; set; }
}
}
使用示例
下面是如何集成和使用上述备份恢复服务的示例代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AppBackup
{
/// <summary>
/// 备份服务使用示例
/// </summary>
publicclass 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("备份服务已关闭");
}
}
}
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();
}
}
}
高级功能实现
备份文件加密保护
对于包含敏感数据的应用,建议实现备份文件加密:
备份文件压缩
对于大型数据库,添加压缩功能可以节省大量存储空间:
/// <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"))
{
thrownew 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;
}
备份到远程存储
为提高备份安全性,可以实现远程存储功能:
/// <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}");
}
returntrue;
}
catch (Exception ex)
{
LogError($"FTP上传失败: {ex.Message}");
returnfalse;
}
}

总结
本文详细介绍了使用C#开发SQLite数据库备份与恢复服务的完整解决方案。通过实现定期自动备份、手动备份触发、备份文件管理和数据库恢复等核心功能,可以有效保障应用数据的安全性。
此外,我们还探讨了备份加密、压缩和远程存储等高级特性,以及备份策略规划、安全保障和性能优化等最佳实践,帮助开发者构建一个全面而可靠的数据库备份系统。
对于任何依赖SQLite数据库的应用程序,实施本文所述的备份恢复服务将显著提高数据安全性和用户信任度,是专业应用开发不可或缺的重要组成部分。
关键词:C#、SQLite、数据库备份、数据恢复、数据安全、.NET开发、备份策略、数据保护、SQLite管理、数据库维护
阅读原文:https://mp.weixin.qq.com/s/LNj5tZ4x79NJ5gHW22n0Sw
该文章在 2025/4/22 17:57:05 编辑过