#topicpath 壊れかけたハードディスクからコピーできるファイルだけ取り出すため、エラーログ採取機能が付いたコピーソフトをでっち上げました。 #ref(SimpleSync-20061027.png,nolink) &br; ** 言い訳 [#x0ad0575] この手のソフトはたくさんあります。なぜわざわざ作ったかというと、コピーしながら例外のログを採取するだけなので、イメージ通りのものを探すよりも作った方が手っ取り早かったからです。 マルチスレッド化により複雑になってしまいました。%%C#で書いてあるというだけで、中身はよくあるやっつけスクリプトと大差ないレベルです。そんな感じでC#は結構気軽に使っているという例です。%% - 使い捨てなので機能拡張の予定はありません。 - 壊れかけのハードディスクからのサルベージが目的のため、汎用的な同期機能はありません。 - Syncと名乗っていますが、厳密に言うと同期ではありません。コピー先に同名のファイルが存在しないとき、または存在するけどサイズが異なっているときだけコピーするようになっています。更新日時%%やサイズ%%などをチェックして同期するわけではありません。%%言い換えると上書きはしません。%% - ファイルではなくパーティションイメージをバックアップするソフトもあります。⇒[[PartitionRW]] ** ダウンロード [#jdb13268] |ライセンス|パブリックドメイン| |ソース|&ref(SimpleSync-20070304.zip);| |備考|マルチスレッド、進捗表示改善、中止サポート| #include(:VCS2005Exp,notitle) *** 過去のリリース [#s916288a] |ソース|&ref(SimpleSync-20061027.zip);|シングルスレッド、進捗表示が止まる、中止不可能| ** 実装 [#p141c208] 実装で使っているテクニックを紹介します。書式は煩雑な印象がありますが過渡的なもので、C# 3.0ではもっと簡潔なものになるようです。 *** 匿名メソッド [#bc98cf13] 最初にファイルサイズをチェックしてからコピーを開始します。チェックとコピーの処理はどちらも再帰的にディレクトリをたどっているため、再帰処理は共通化して、異なる部分だけを匿名メソッドで渡すようにしました。今流行のクロージャ的な書き方です。ローカル変数がそのまま使えて便利です。 long size = 0, totalSize = 0, count = 0, totalCount = 0; CompareFolder(di1, di2, "", delegate(FileInfo fi1, FileInfo fi2) { SetProgressText("--- / {0:#,##0} MB , --- / {1:#,##0} 個", totalSize / 1024 / 1024, totalCount); if (fi1 == null) return; totalSize += fi1.Length; totalCount++; }); if (totalSize == 0) totalSize = 1; CompareFolder(di1, di2, "", delegate(FileInfo fi1, FileInfo fi2) { CopyFile(fi1, fi2, delegate(long pos) { SetProgressText( "{0:#,##0} / {1:#,##0} MB ({2} %) , {3:#,##0} / {4:#,##0} 個", (size + pos) / 1024 / 1024, totalSize / 1024 / 1024, size * 100 / totalSize, count, totalCount); }, delegate { size += fi1.Length; count++; }); }); メソッドにブロックを渡すような感じです。元々あった委譲の概念を拡張(この場合は定義のインライン化)して実装されているため、関数型言語のようにアプリオリに実装されているよりも理解しやすいと思いました。 C# 3.0ではラムダ式という簡単な書式が使用できるようになりました。 [C# 2.0] delegate(FileInfo fi1, FileInfo fi2) {} [C# 3.0] (fi1, fi2) => {} *** 汎用delegate [#d89dfbb0] 既存のメソッドをdelegateとして渡すときにキャストをすると簡潔に記述できます。delegateを汎用的に表現しているAction<>を使うと、いちいちdelagateを定義する必要がないため便利です。 private void SetLabelText(Label label, string t) { label.Text = t; } private void SetFolderLabel(string t) { Invoke((Action<Label, string>)SetLabelText, label3, t); } ** コメント [#pca80038] #comment(below)