10

私は自分用に単純なフォルダー同期バックアップ ツールを作成していますが、File.Copy を使用してかなりの障害に遭遇しました。~44,000 個の小さなファイル (Windows メール フォルダー) のフォルダーをシステム内の別のドライブにコピーするテストを行ったところ、File.Copy を使用すると、コマンド ラインを使用して xcopy を実行して同じファイル/フォルダーをコピーするよりも 3 倍以上遅いことがわかりました。私の C# バージョンでは、ファイルのコピーに 16 分以上かかりますが、xcopy では 5 分しかかかりません。このトピックに関するヘルプを検索してみましたが、ネットワークを介した大きなファイルのコピーが遅いと不満を言う人しか見つかりませんでした。これは、大きなファイルの問題でも、ネットワーク コピーの問題でもありません。

より良い File.Copy 置換に関する興味深い記事を見つけましたが、投稿されたコードにはスタックに問題を引き起こすエラーがいくつかあり、彼のコードの問題を修正するのに十分な知識はありません。

File.Copy をより高速なものに置き換える一般的または簡単な方法はありますか?

4

5 に答える 5

9

考慮すべきことの 1 つは、コピー中に更新されるユーザー インターフェイスがコピーにあるかどうかです。その場合は、コピーが別のスレッドで実行されていることを確認してください。そうしないと、コピー中に UI がフリーズし、UI を更新するためにブロック呼び出しを行うことでコピーが遅くなります。

私は同様のプログラムを作成しましたが、私の経験では、私のコードは Windows エクスプローラーのコピーよりも高速に実行されました (xcopyコマンド プロンプトからはわかりません)。

また、UI がある場合は、すべてのファイルを更新しないでください。代わりに、X メガバイトごとまたは Y ファイルごと (どちらか早い方) を更新します。これにより、UI が実際に処理できる更新の量が抑えられます。私は .5MB または 10 個のファイルごとに使用しました。これらは最適ではないかもしれませんが、コピー速度と UI の応答性が著しく向上しました。

高速化するもう 1 つの方法は、Get 関数の代わりに (たとえばEnumerateFilesの代わりにGetFiles) Enumerate 関数を使用することです。これらの関数は、リストの構築が完了したときにすべてを返すのを待つのではなく、できるだけ早く結果を返し始めます。それらは Enumerable を返すので、結果に対して foreach を呼び出すことができます: foreach(string file in System.IO.Directory.EnumerateDirectories(path)). 私のプログラムでは、これは速度にも顕著な違いをもたらしました。多くのファイル。

于 2012-07-06T23:24:53.953 に答える
5

回転ディスクで IO 操作を最も遅くする原因の 1 つは、ディスク ヘッドの移動です。

多くの小さなファイル (すべてが相互に関連している) は、コピーの宛先に近いよりもディスク上で近くにあると想定するのが合理的であり、おそらく非常に正確です (ディスクの一部からコピーしていると仮定すると)同じディスクの別の部分に)。少しコピーしてから少し書き込むと、他のプロセスがソース ディスクまたはターゲット ディスクのディスク ヘッドを移動する機会が開かれます。

XCopy が Copy (どちらの場合もコマンドを意味する) よりもはるかに優れていることの 1 つは、XCopy が、それらのファイルを宛先に書き出す前に、一連のファイルを読み取ることです。

同じディスクにファイルをコピーする場合は、大きなバッファを割り当てて一度に多くのファイルを読み込み、バッファがいっぱいになったらそれらのファイルを書き出すようにしてください)。

あるディスクから読み取り、別のディスクに書き込む場合は、1 つのスレッドを起動してソース ディスクから読み取り、別のスレッドを起動して別のディスクに書き込みます。

于 2012-07-06T23:02:41.647 に答える
3

より高速なファイル コピーには、次の 2 つのアルゴリズムがあります。

ソースと宛先が異なるディスクの場合:

  • 1 つのスレッドがファイルを継続的に読み取り、バッファーに格納します。
  • 別のスレッドがそのバッファから継続的にファイルを書き込んでいます。

ソースと宛先が同じディスクの場合:

  • ファイル数に関係なく、一度に 8K などの一定のバイト単位を読み取ります。
  • その固定チャンクを 1 つのファイルまたは複数のファイルの宛先に書き込みます。

このようにして、重要なパフォーマンスが得られます。

別の方法として、.net コードから xcopy を呼び出すだけです。File.Copy を使用してわざわざそれを行うのはなぜですか。Process.StandardOutput を使用して xcopy 出力をキャプチャし、何が起こっているかをユーザーに示すために画面に表示できます。

于 2012-07-09T14:24:44.940 に答える
1

少なくとも2つのファイルを同時に実行できるように、それを並列化できると思います。あるスレッドが書き込みを行っている間、別のスレッドはすでに次のファイルを読み取っている可能性があります。あなたがファイルのリストを持っているなら、あなたはこのようにそれをすることができます。多くのスレッドを使用すると、ドライブが順番に書き込むことができずに、より多く移動するため、役に立ちません。

 var files = new List<string>();
 // todo: fill the files list using directoryenumeration or so...
 var po = new ParallelOptions() {MaxDegreeOfParallelism = 2};
 Parallel.ForEach(files, po, CopyAFile);

 // Routine to copy a single file
 private void CopyAFile(string file) { }
于 2012-07-09T11:34:03.627 に答える
0

このレベルでは良い経験がありません。xcopy コマンドを含むバッチ ファイルを実行してみませんか? この投稿を確認してください: C# でバッチ ファイルを実行する

于 2012-07-06T23:05:31.753 に答える