初めまして。
テストファイルの作成のため、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;
すいません。テストで色々やったため変なコードが残ってました。
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;
メモリの確保と解放を繰り返しているからでは?
一旦、それなりのバッファを確保しておいて
足りない場合再確保してみるとか。。。
もしくは、読み込みスレッドと書き込みスレッドを用意して同期処理してみる。
もちろん、書き込みより読み込みのプライオリティは高く設定
TMemoryStreamのLoadFromFileは内部でメモリの再割り当てをするので、その繰り返しが多いと問題が出ると思う。
なので、TMemoryStreamは使わずに、TFileStreamと固定バッファを使う案に1票。
数百万回繰り返すのは、SaveToFileだけだね。
でも、SaveToFileだけでも、内部でTFileStreamの生成と破棄がその回数だけ繰り返されるのは問題かな。
Streamを使わず、FileCreate、FileWriteなど低レベルのファイルアクセスルーチンならどうかな?
CountUp関数で文字列操作を数百万回繰り返すのも問題じゃないの?
ガベージコレクションで実行速度が落ちるのかも。
耐久試験さんの案にも一票
また、固定バッファに1票さんも言われているように、
「TMemoryStreamのLoadFromFileは内部でメモリの再割り当て」
を行っているみたいなので、GetMemとか使ってみるとか。。。?
(GetMemのヘルプとか見てないけどw)
そもそもCopyFileとか使っちゃいけないんでしょうか。
それともコピーしてるのはあくまで実験のためで
本当は中身を加工しながら書き出したいとか?
たくさんの回答ありがとうございます。
OSのboot障害により修復作業を行って遅くなりました。
情報が小出しですいませんでした。
メモリの確保と解放は、この問題の解決策に繋がると思い、追加したものです。
>でも、SaveToFileだけでも、内部でTFileStreamの生成と破棄がその回数だけ繰り返されるのは問題かな。
>Streamを使わず、FileCreate、FileWriteなど低レベルのファイルアクセスルーチンならどうかな?
ありがとうございます。FileWriteで動作させてみたいのですが、実装方法が理解できませんでした。
var
fh :Integer;
begin
fh := FileOpen(OpenFileName, fmOpenWrite);
FileSeek(fh, 0, 2);
FileWrite(fh,この先の二つの引数がわかりません)
end;
よろしければこの部分教えて下さい。
>そもそもCopyFileとか使っちゃいけないんでしょうか。
件数が膨大なため、速度に影響が出そうなので使用を控えましたが、
私の勘違いでしたら、すいません。
ヘルプにはどのように書いていますか?
バッファと書き込みサイズですよ
ヘルプにはどのように書いていますか?
バッファと書き込みサイズですよ
ファイルの数を極端に増やした際の書き込み遅延はwindowsのファイルシステムの仕様です。
少しでも低速化を軽減したいのであれば、
ハードディスクの設定で、
検索用インデックスを付加しない、
圧縮しない、暗号化しない
フォーマット時のアロケーションユニットサイズを最少にする
究極は、「一つのファイルとして保存する」です。
そうすれば、ディスクフォーマットの影響を受けません
ツイート | ![]() |