【转载】+【原创】C#版SQLite的备份和还原

红线以内是转载:http://simon-hardy.com/Blog/Home/Details/backup-and-restore-from-sqlitenet

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Backup from SQLite.Net

            Without a server process to run maintenance tasks, applications that use SQLite to store data must perform those tasks themselves. Backup and restore is the most commonly needed of these tasks. So I'll cover how I do that here.        

Context

    SQLite Backup Context

Backup

API Support

SQLite.net provides an API method on a SQLiteConnection object to perform the SQLite backup operation.
In order to call this method you need to pass the following parameters:
       
  • destination - An open SQLiteConnection for the destination database;   
  • destinationName - "main" to backup to the main database file, "temp" to backup to the temporary database file, or the name specified after the AS keyword in an ATTACH statement for an attached database;   
  • sourceName - "main" to backup from the main database file, "temp" to backup from the temporary database file, or the name specified after the AS keyword in an ATTACH statement for an attached database;   
  • pages - the number of pages on disk to back up with every iteration of the algorithm, -1 will backup the whole database in one iteration;   
  • callback - a function that is called between every iteration, returns true to continue, or false to stop the algorithm;   
  • retryMilliseconds - number of milliseconds to wait before retrying a failed iteration of the algorithm.

Extending with IObservable<T> and IObserver<T>

The following class wraps the iterative algorithm within an IObservable<SqliteBackupEvent> object. The SqliteBackupEvent class just contains the properties returned to the callback:
   
   1:  public class SqliteBackup : IObservable<SqliteBackupEvent>
   2:  {
   3:      private readonly List<IObserver<SqliteBackupEvent>> _observers;
   4:   
   5:      public SqliteBackup()
   6:      {
   7:          _observers = new List<IObserver<SqliteBackupEvent>>();
   8:      }
   9:   
  10:      public void Execute(string sourceConnectionString, string destinationConnectionString, int pagesToBackupInEachStep)
  11:      {
  12:          try
  13:          {
  14:              using (var srcConnection = new SQLiteConnection(sourceConnectionString))
  15:              using (var destConnection = new SQLiteConnection(destinationConnectionString))
  16:              {
  17:                  srcConnection.Open();
  18:                  destConnection.Open();
  19:   
  20:                  // Need to use the "main" names as specified at http://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupinit
  21:                  srcConnection.BackupDatabase(destConnection, "main", "main", pagesToBackupInEachStep, Callback, 10);
  22:   
  23:                  destConnection.Close();
  24:                  srcConnection.Close();
  25:              }
  26:          }
  27:          catch (Exception ex)
  28:          {
  29:              foreach (var observer in _observers)
  30:                  observer.OnError(ex);
  31:          }
  32:   
  33:          foreach (var observer in _observers)
  34:              observer.OnCompleted();
  35:      }
  36:   
  37:      protected virtual bool Callback(SQLiteConnection srcConnection, string srcName, SQLiteConnection destConnection, string destName,
  38:                                      int pages, int remaining, int pageCount, bool retry)
  39:      {
  40:          var @event = new SqliteBackupEvent(pages, remaining, pageCount, retry);
  41:   
  42:          foreach (var observer in _observers)
  43:              observer.OnNext(@event);
  44:   
  45:          return true;
  46:      }
  47:   
  48:      public IDisposable Subscribe(IObserver<SqliteBackupEvent> observer)
  49:      {
  50:          if (!_observers.Contains(observer))
  51:              _observers.Add(observer);
  52:          return new Unsubscriber(_observers, observer);
  53:      }
  54:   
  55:      private class Unsubscriber : IDisposable
  56:      {
  57:          private readonly List<IObserver<SqliteBackupEvent>> _observers;
  58:          private readonly IObserver<SqliteBackupEvent> _observer;
  59:   
  60:          public Unsubscriber(List<IObserver<SqliteBackupEvent>> observers, IObserver<SqliteBackupEvent> observer)
  61:          {
  62:              this._observers = observers;
  63:              this._observer = observer;
  64:          }
  65:   
  66:          public void Dispose()
  67:          {
  68:              if (_observer != null && _observers.Contains(_observer))
  69:                  _observers.Remove(_observer);
  70:          }
  71:      }
  72:  }
For completeness the SqliteBackupEvent class should be:
   1:  public class SqliteBackupEvent
   2:      {
   3:          public int Pages { get; private set; }
   4:          public int Remaining { get; private set; }
   5:          public int PageCount { get; private set; }
   6:          public bool Retry { get; private set; }
   7:   
   8:          public SqliteBackupEvent(int pages, int remaining, int pageCount, bool retry)
   9:          {
  10:              Pages = pages;
  11:              Remaining = remaining;
  12:              PageCount = pageCount;
  13:              Retry = retry;
  14:          }
  15:      }
This can be used to update a GUI or some other form of output, such as logging, with the status of the backup operation:
   
   1:  public class ConsoleWriterObserver : IObserver<SqliteBackupEvent>
   2:  {
   3:      public void OnNext(SqliteBackupEvent value)
   4:      {
   5:          Console.WriteLine("{0} - {1} - {2} - {3}", value.Pages, value.PageCount, value.Remaining, value.Retry);
   6:      }
   7:   
   8:      public void OnError(Exception error)
   9:      {
  10:          Console.WriteLine(error.Message);
  11:      }
  12:   
  13:      public void OnCompleted()
  14:      {
  15:          Console.WriteLine("Complete");
  16:      }
  17:  }
The use of these classes in your appilcation then becomes something like:
   1:  const string srcConnectionString = @"Data Source="".\data.db"";Version=3;";
   2:  const string destConnectionString = @"Data Source="".\newdata.db"";Version=3;";
   3:   
   4:  var backup = new SqliteBackup();
   5:   
   6:  var unsubscriber = backup.Subscribe(new ConsoleWriterObserver());
   7:   
   8:  backup.Execute(srcConnectionString, destConnectionString, 50);
   9:   
  10:  unsubscriber.Dispose();
  11:   
  12:  Console.ReadLine();

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

一下是根据自己的实际情况写的一个简易版的备份和还原

备份数据库:
 1         public void BackUpDateBase()
 2         {
 3             string destDBFileName = configMng.backUpFileName;
 4             int index = destDBFileName.IndexOf('.');
 5             string destDBFileNameProcess = destDBFileName.Insert(index, "_process");
 6             SQLiteConnection cnDest = new SQLiteConnection(@"Data Source=" + configMng.backUpPath + @"\" + destDBFileNameProcess);
 7             SQLiteConnection cnSource = new SQLiteConnection(@"Data Source=..\DataBase\" + configMng.backUpFileName);
 8             try
 9             {
10                 cnDest.Open();
11                 cnSource.Open();
12 
13                 cnSource.BackupDatabase(cnDest, "main", "main", -1, null, 0);
14                 cnDest.Close();
15                 cnSource.Close();
16 
17                 if (File.Exists(configMng.backUpPath + @"\" + destDBFileNameProcess))
18                 {
19                     destDBFileName = destDBFileName.Insert(index, DateTime.Now.ToString("yyyyMMddHHmmss"));
20                     File.Move(configMng.backUpPath + @"\" + destDBFileNameProcess, configMng.backUpPath + @"\" + destDBFileName);
21                 }
22             }
23             catch(Exception e)
24             {
25                 LogHelper.WiteLog("SQLiteBackUpService backup faild!");
26                 if (cnDest.State == ConnectionState.Open)
27                 {
28                     cnDest.Close();
29                 }
30                 if (cnSource.State == ConnectionState.Open)
31                 {
32                     cnSource.Close();
33                 }
34 
35             }
36 
37         } 

 红色代码部分就是用于数据库的备份的,这时SQLite提供的在线备份,好处是备份的同时不会影响数据库的使用,当然这个函数也可以用于数据库的还原,

这个函数后几个参数可以实现备份时的进度反馈,

例如下面的用法,就能反映进度:

cnSource.BackupDatabase(cnDest, "main", "main", 2, Callback, -1);



        protected bool Callback(SQLiteConnection srcConnection, string srcName, SQLiteConnection destConnection, string destName,
                                       int pages, int remaining, int pageCount, bool retry)
        {
            process = 100 *(pageCount - remaining) / pageCount;
            if (remaining <= pages)
            {
                isRestore = false;
                process = 100;
            }
            return true;
        }

上述代码中BackupDatabase()函数在备份的过程中就能回调Callback函数,他调用的频率是由第四个参数决定的,当前为2表示每备份2页就调用callback,

在callback函数中,pagecount就是当前备份的数据库的总页数,remaining就是还没备份的,pages就是前面的2(备份的频率)。

 



posted @ 2014-07-11 14:45  yaoxiaping666  Views(2953)  Comments(0Edit  收藏  举报