ソースコードはこちら
https://github.com/mi3w2a1/incremental-backup
前回の続きです。バックアップ先からファイルを復元する処理を考えます。
[バックアップ先から復元]をクリックすると以下のようなダイアログを表示されます。このなかからバックアップされた時刻と復元先フォルダを指定すると、バックアップ先からファイルとフォルダが復元されます。
復元先フォルダは空のフォルダでなければなりません(復元先フォルダのなかに同名のファイルがあると処理が複雑になるので・・・)。
[復元]ボタンがクリックされると適切な値が設定されているか調べます。「適切」であるとは、復元時刻が指定されていること、復元先フォルダのパスが指定されていること、復元先フォルダは実際に存在し、中身は空であること、これらすべての条件を満たしていることです。そのときはダイアログは閉じられて、ファイルの復元の処理がはじまります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
public partial class FormRestore : Form { public FormRestore() { InitializeComponent(); } public List<long> TicksList = null; public string SelectedPath = ""; public long RestoreTime = 0; private void FormRestore_Load(object sender, EventArgs e) { if(TicksList == null) return; foreach(long ticks in TicksList) { DateTime dt = new DateTime(ticks); string str = dt.ToString("yyyy年 MM月 dd日 HH時 mm分 ss秒"); listBox1.Items.Add(str); } } private void button1_Click(object sender, EventArgs e) { FolderBrowserDialog dialog = new FolderBrowserDialog(); if(dialog.ShowDialog() == DialogResult.OK) { SelectedPath = dialog.SelectedPath; } dialog.Dispose(); } private void button2_Click(object sender, EventArgs e) { if(listBox1.SelectedIndex == -1) { MessageBox.Show("復元時刻が指定されていません!", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } if(SelectedPath == "") { MessageBox.Show("復元先フォルダのパスが指定されていません!", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } if(!Directory.Exists(SelectedPath)) { MessageBox.Show("指定された復元先フォルダは存在しません!", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } string[] vs1 = Directory.GetFiles(SelectedPath, "*.*", SearchOption.TopDirectoryOnly); string[] vs2 = Directory.GetDirectories(SelectedPath, "*.*", SearchOption.TopDirectoryOnly); if(vs1.Length != 0 || vs2.Length != 0) { MessageBox.Show("復元先フォルダは空のフォルダを指定してください!", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } long ticks = TicksList[listBox1.SelectedIndex]; DateTime dt = new DateTime(ticks); string str = dt.ToString("yyyy年 MM月 dd日 HH時 mm分 ss秒"); string mes = String.Format("フォルダ {0} に\n{1} のファイルとフォルダを復元します", SelectedPath, str); if(MessageBox.Show(mes, "確認", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK) { RestoreTime = ticks; this.Close(); } } } |
[バックアップ先から復元]をクリックするとForm1クラスでは以下のメソッドが実行されます。
GetRestoreTicksList(string targetFolder)メソッドはログが保存されているフォルダからログファイルのパスを取得し、そのファイル名から復元可能な時刻をリストに格納します。ファイル名から復元可能な時刻を求めるのがGetTicksFromLogFilePath(string filePath)メソッドです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
public partial class Form1 : Form { List<long> GetRestoreTicksList(string targetFolder) { string[] filePaths = Directory.GetFiles(GetLogFolderPath(targetFolder), "*.txt", SearchOption.TopDirectoryOnly); List<long> ticksList = new List<long>(); foreach(string path in filePaths) { ticksList.Add(GetTicksFromLogFilePath(path)); } return ticksList.OrderByDescending(x => x).ToList(); } long GetTicksFromLogFilePath(string filePath) { FileInfo info = new FileInfo(filePath); string name = info.Name; string year = name.Substring(0, 4); string month = name.Substring(5, 2); string day = name.Substring(7, 2); string hour = name.Substring(10, 2); string minute = name.Substring(12, 2); string second = name.Substring(14, 2); DateTime dt = new DateTime(int.Parse(year), int.Parse(month), int.Parse(day), int.Parse(hour), int.Parse(minute), int.Parse(second)); return dt.Ticks; } } |
復元可能な時刻がリストに格納されたら、これを上記のFormRestoreクラスのフィールド変数 FormRestore.TicksListにセットします。そのあとShowDialog()メソッドを実行してダイアログを表示させます。
ダイアログで適切な値が設定されていた場合([復元]ボタンがクリックされ、FormRestoreダイアログが正常に閉じられたときはFormRestore.RestoreTimeが0よりも大きな値になっている)は、ファイル復元の処理がおこなわれます。
ファイルを復元するためにはログファイルと GetRestoreTicksList(string targetFolder) で取得されたもののうち、FormRestore.RestoreTimeと同じものか、それよりも数値が小さいものを使います。まずFormRestore.RestoreTimeからバックアップしているフォルダパスを求め、そのフォルダのなかに復元しようとしているファイルがあるかどうか調べます。
GetBackupFolderPaths(long time, List<long> ticksList)メソッドは、指定された時刻からバックアップされているフォルダパスのリストを取得するためのメソッドです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public partial class Form1 : Form { List<string> GetBackupFolderPaths(long time, List<long> ticksList) { List<long> vs = ticksList.Where(x => x <= time).ToList(); vs = vs.OrderByDescending(x => x).ToList(); List<string> backupFolderPaths = new List<string>(); string logPath = GetLogFilePathFromTicks(time); foreach(long ticks in vs) { backupFolderPaths.Add(GetFolderPathFromTicks(ticks)); } return backupFolderPaths; } } |
バックアップされているファイルが見つかった場合は復元先のフォルダにそのままコピーし、なければFormRestore.RestoreTimeに近い順にバックアップしているフォルダパスを求め、そこを探します。どこかでバックアップされているファイルとフォルダは見つかるはずなのですが、見つからない場合はエラーとなります。
これはファイルとフォルダがバックアップされているフォルダパスのリストから実際にファイルとフォルダを復元するためのメソッドです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
public partial class Form1 : Form { void RestoreFiles(string folderPath, string logFilePath, List<string> backupFolderPaths, string sourceFolderPath) { StreamReader sr = new StreamReader(logFilePath); string str = sr.ReadToEnd(); string[] vs1 = str.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries); foreach(string path in vs1) { string[] vs2 = path.Split(new string[] { "::" }, StringSplitOptions.RemoveEmptyEntries); if(vs2.Length != 2) { MessageBox.Show("ログファイルが破損しています!", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } string filePath = vs2[0].Replace(sourceFolderPath, folderPath); bool isFind = false; foreach(string backupFolderPath in backupFolderPaths) { string backupFilePath1 = vs2[0].Replace(sourceFolderPath, backupFolderPath); if(File.Exists(backupFilePath1)) { File.Copy(backupFilePath1, filePath); isFind = true; break; } if(Directory.Exists(backupFilePath1)) { string newFolderPath = vs2[0].Replace(sourceFolderPath, folderPath); Directory.CreateDirectory(newFolderPath); isFind = true; break; } } if(!isFind) MessageBox.Show("エラー ファイルがみつからない", vs2[0], MessageBoxButtons.OK, MessageBoxIcon.Error); } MessageBox.Show("復元完了"); } } |
最後に[バックアップ先から復元]をクリックしたときにForm1クラスで呼び出されるメソッドを示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
public partial class Form1 : Form { private void RestoreFilesMenuItem_Click(object sender, EventArgs e) { string targetFolder = GetTargetFolderPath(); if(targetFolder == "") { MessageBox.Show("項目が選択されていません!", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } if(!Directory.Exists(GetLogFolderPath(targetFolder))) { MessageBox.Show("バックアップは存在しません", "報告", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } List<long> ticksList = GetRestoreTicksList(targetFolder); FormRestore form = new FormRestore(); form.TicksList = ticksList; form.ShowDialog(); if(form.RestoreTime > 0) { string folderPath = form.SelectedPath; long time = form.RestoreTime; List<long> vs = form.TicksList; List<string> backupFolderPaths = GetBackupFolderPaths(time, vs); string logPath = GetLogFilePathFromTicks(time); RestoreFiles(folderPath, logPath, backupFolderPaths, GetSourceFolderPath()); } form.Dispose(); } } |