Top / SimpleSync

壊れかけたハードディスクからコピーできるファイルだけ取り出すため、エラーログ採取機能が付いたコピーソフトをでっち上げました。

SimpleSync-20061027.png


言い訳

この手のソフトはたくさんあります。なぜわざわざ作ったかというと、コピーしながら例外のログを採取するだけなので、イメージ通りのものを探すよりも作った方が手っ取り早かったからです。

マルチスレッド化により複雑になってしまいました。C#で書いてあるというだけで、中身はよくあるやっつけスクリプトと大差ないレベルです。そんな感じでC#は結構気軽に使っているという例です。

ダウンロード

ライセンスパブリックドメイン
ソースfileSimpleSync-20070304.zip
備考マルチスレッド、進捗表示改善、中止サポート

過去のリリース

ソースfileSimpleSync-20061027.zipシングルスレッド、進捗表示が止まる、中止不可能

実装

実装で使っているテクニックを紹介します。書式は煩雑な印象がありますが過渡的なもので、C# 3.0ではもっと簡潔なものになるようです。

匿名メソッド

最初にファイルサイズをチェックしてからコピーを開始します。チェックとコピーの処理はどちらも再帰的にディレクトリをたどっているため、再帰処理は共通化して、異なる部分だけを匿名メソッドで渡すようにしました。今流行のクロージャ的な書き方です。ローカル変数がそのまま使えて便利です。

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ではこれをラムダ式にまで拡張するそうです。

汎用delegate

引数が1つのdelegateを汎用的に表現しているAction<>を使うと、いちいちdelagateを定義する必要がないため便利です。それを真似して引数が2つのAction2<,>も定義しました。

private delegate void Action2<T1, T2>(T1 obj1, T2 obj2);

既存のメソッドをdelegateとして渡すときにキャストをすると簡潔に記述できます。

private void SetLabelText(Label label, string t)
{
    label.Text = t;
}

private void SetFolderLabel(string t)
{
    Invoke((Action2<Label, string>)SetLabelText, label3, t);
}

C# 3.0では自動型推論が働くため、明示的なキャストが不要になるようです。

コメント


トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS