ファイルの大量コピーを早く行う方法は?


karu  2008-07-13 21:37:40  No: 31210

初めまして。
テストファイルの作成のため、1つのjpg画像(50k程度)を数百万件の
コピーを行いたいのですが、10数万件を超えたあたりで速度が低下してしまい、
対策が見つかりません。Windowsの問題かもしれませんが解決策や代替の案が
ありましたら、どうぞよろしくお願い致します。
環境はWindowsXP。Thread内でファイルコピーを行っています。
出来ることならGUIで作成したいと思います。

procedure TMyThread.Execute;
var
  mstm: TMemoryStream;
  OpenFileName, SaveFileName, File_Name: String;
  i : Integer;
  CopyCount :Integer;
begin
  roopflg := True;
  File_Name := MainForm.FileName_Edit.Text;

  OpenFileName := MainForm.TargetFileName_Edit.text;
  SaveFileName := MainForm.SaveFolder_Edit.Text +'\';
  CopyCount := StrToInt(MainForm.CopyCount_Edit.text);

  mstm := TMemoryStream.Create;

  try
    mstm.LoadFromFile(OpenFileName);

      for i := 1 to CopyCount do
      begin

        //TMemoryStreamを定期的にFreeして実験
        if ((i mod 10000) = 0) do
        begin
          mstm.Free;
          mstm := TMemoryStream.Create;
          mstm.LoadFromFile(OpenFileName);
        end;

        mstm.SaveToFile(SaveFileName + File_Name + IntTostr(i)+ '.jpg');
        FCount := i;
        Synchronize( CountUp );

      end;
    finally
      mstm.Free;
    end;

end;


karu  2008-07-13 21:41:18  No: 31211

すいません。テストで色々やったため変なコードが残ってました。

procedure TMyThread.Execute;
var
  mstm: TMemoryStream;
  OpenFileName, SaveFileName, File_Name: String;
  i : Integer;
  CopyCount :Integer;
begin
  File_Name := MainForm.FileName_Edit.Text;

  OpenFileName := MainForm.TargetFileName_Edit.text;
  SaveFileName := MainForm.SaveFolder_Edit.Text +'\';
  CopyCount := StrToInt(MainForm.CopyCount_Edit.text);

  mstm := TMemoryStream.Create;

  try
    mstm.LoadFromFile(OpenFileName);

      for i := 1 to CopyCount do
      begin

        //TMemoryStreamを定期的にFreeして実験
        if ((i mod 10000) = 0) then
        begin
          mstm.Free;
          mstm := TMemoryStream.Create;
          mstm.LoadFromFile(OpenFileName);
        end;

        mstm.SaveToFile(SaveFileName + File_Name + IntTostr(i)+ '.jpg');
        FCount := i;
        Synchronize( CountUp );

      end;
   finally
     mstm.Free;
   end;

end;

procedure TMyThread.CountUp;
begin
  MainForm.Count_Label.Caption := IntToStr(FCount) + '/'+ MainForm.CopyCount_Edit.Text;
end;


スレッドは知らないけどw  2008-07-13 22:31:23  No: 31212

メモリの確保と解放を繰り返しているからでは?

一旦、それなりのバッファを確保しておいて
足りない場合再確保してみるとか。。。


スレッドは知ってるけどw  2008-07-13 22:51:02  No: 31213

もしくは、読み込みスレッドと書き込みスレッドを用意して同期処理してみる。
もちろん、書き込みより読み込みのプライオリティは高く設定


固定バッファに1票  2008-07-14 00:21:43  No: 31214

TMemoryStreamのLoadFromFileは内部でメモリの再割り当てをするので、その繰り返しが多いと問題が出ると思う。
なので、TMemoryStreamは使わずに、TFileStreamと固定バッファを使う案に1票。


耐久試験?  2008-07-14 01:57:40  No: 31215

数百万回繰り返すのは、SaveToFileだけだね。
でも、SaveToFileだけでも、内部でTFileStreamの生成と破棄がその回数だけ繰り返されるのは問題かな。
Streamを使わず、FileCreate、FileWriteなど低レベルのファイルアクセスルーチンならどうかな?


文字列操作は?  2008-07-14 02:16:32  No: 31216

CountUp関数で文字列操作を数百万回繰り返すのも問題じゃないの?
ガベージコレクションで実行速度が落ちるのかも。


ある意味耐久試験  2008-07-14 03:12:30  No: 31217

耐久試験さんの案にも一票
また、固定バッファに1票さんも言われているように、
「TMemoryStreamのLoadFromFileは内部でメモリの再割り当て」
を行っているみたいなので、GetMemとか使ってみるとか。。。?
(GetMemのヘルプとか見てないけどw)


ttt  2008-07-14 04:13:44  No: 31218

そもそもCopyFileとか使っちゃいけないんでしょうか。
それともコピーしてるのはあくまで実験のためで
本当は中身を加工しながら書き出したいとか?


karu  2008-07-14 22:49:05  No: 31219

たくさんの回答ありがとうございます。
OSのboot障害により修復作業を行って遅くなりました。

情報が小出しですいませんでした。
メモリの確保と解放は、この問題の解決策に繋がると思い、追加したものです。

>でも、SaveToFileだけでも、内部でTFileStreamの生成と破棄がその回数だけ繰り返されるのは問題かな。
>Streamを使わず、FileCreate、FileWriteなど低レベルのファイルアクセスルーチンならどうかな?

ありがとうございます。FileWriteで動作させてみたいのですが、実装方法が理解できませんでした。

var
  fh :Integer;
begin

  fh := FileOpen(OpenFileName, fmOpenWrite);
  FileSeek(fh, 0, 2);
  FileWrite(fh,この先の二つの引数がわかりません)

end;

よろしければこの部分教えて下さい。

>そもそもCopyFileとか使っちゃいけないんでしょうか。
件数が膨大なため、速度に影響が出そうなので使用を控えましたが、
私の勘違いでしたら、すいません。


FileWrite  2008-07-15 07:07:21  No: 31220

ヘルプにはどのように書いていますか?

バッファと書き込みサイズですよ


FileWrite  2008-07-15 07:07:22  No: 31221

ヘルプにはどのように書いていますか?

バッファと書き込みサイズですよ


もにゃ  2008-07-15 08:04:58  No: 31222

ファイルの数を極端に増やした際の書き込み遅延はwindowsのファイルシステムの仕様です。

少しでも低速化を軽減したいのであれば、
ハードディスクの設定で、
  検索用インデックスを付加しない、
  圧縮しない、暗号化しない
  フォーマット時のアロケーションユニットサイズを最少にする

究極は、「一つのファイルとして保存する」です。
そうすれば、ディスクフォーマットの影響を受けません


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加