delphi7-に書かれているファイルをコピーするにはどうすればよいですか
-
11-10-2019 - |
質問
マスターPCで毎日毎日テキストファイルに情報を記録するアプリケーションがあります。同じアプリケーションを使用してネットワーク上のスレーブPCは、このテキストファイルをローカルドライブにコピーしたいと考えています。ファイルアクセスの問題があることがわかります。
これらのファイルは、それぞれ30〜40MBを超えるものでなければなりません。ネットワークは100MBのイーサネットになります。コピープロセスが1秒以上かかる可能性があることがわかります。つまり、ロギングPCが読み取り中にファイルを開く必要があることを意味します。
ファイルの書き込み(ロギング)とファイルのコピー手順に最適な方法は何ですか?標準のWindows CopyFile()手順があることは知っていますが、これによりファイルアクセスの問題が発生しました。 FMSharedenynoneフラグを使用するTfilestreamもありますが、これは非常に時折アクセスの問題をもたらします(週1週間など)。
これがこのタスクを達成するための最良の方法は何ですか?
私の現在のファイルのロギング:
procedure FSWriteline(Filename,Header,s : String);
var LogFile : TFileStream;
line : String;
begin
if not FileExists(filename) then
begin
LogFile := TFileStream.Create(FileName, fmCreate or fmShareDenyNone);
try
LogFile.Seek(0,soFromEnd);
line := Header + #13#10;
LogFile.Write(line[1],Length(line));
line := s + #13#10;
LogFile.Write(line[1],Length(line));
finally
logfile.Free;
end;
end else begin
line := s + #13#10;
Logfile:=tfilestream.Create(Filename,fmOpenWrite or fmShareDenyNone);
try
logfile.Seek(0,soFromEnd);
Logfile.Write(line[1], length(line));
finally
Logfile.free;
end;
end;
end;
私のファイルコピー手順:
procedure DoCopy(infile, Outfile : String);
begin
ForceDirectories(ExtractFilePath(outfile)); //ensure folder exists
if FileAge(inFile) = FileAge(OutFile) then Exit; //they are the same modified time
try
{ Open existing destination }
fo := TFileStream.Create(Outfile, fmOpenReadWrite or fmShareDenyNone);
fo.Position := 0;
except
{ otherwise Create destination }
fo := TFileStream.Create(OutFile, fmCreate or fmShareDenyNone);
end;
try
{ open source }
fi := TFileStream.Create(InFile, fmOpenRead or fmShareDenyNone);
try
cnt:= 0;
fi.Position := cnt;
max := fi.Size;
{start copying }
Repeat
dod := BLOCKSIZE; // Block size
if cnt+dod>max then dod := max-cnt;
if dod>0 then did := fo.CopyFrom(fi, dod);
cnt:=cnt+did;
Percent := Round(Cnt/Max*100);
until (dod=0)
finally
fi.free;
end;
finally
fo.free;
end;
end;
解決
共有ファイルを何度も何度も閉じたり再開したりしないことをお勧めします。あなたは毎秒それに書くので、それはただ不必要なオーバーヘッドです。
マスター側で、ファイルを作成して閉じます( fmCreate
フラグは他のフラグでは使用できません!) fmOpenWrite
でモード fmShareDenyWrite
共有し、開いたままにして、必要に応じて書き込みます。
スレーブ側に、ファイルを開きます fmOpenRead
でモード fmShareDenyNone
共有し、開いたままにして、毎秒読んでください。共有ファイル全体を毎回ネットワーク上にコピーする必要はありません。それは無駄な帯域幅です。過去数秒で書かれた新しいデータを読んでください。それだけです。スレーブがローカルファイルにデータを保存する必要がある場合、共有ファイルから独立して個別のローカルファイルを管理し、必要に応じて新しいデータをローカルファイルに押し込みます。
他のヒント
あなたの特定の時折の繰り返しの問題に対処するため:
使用しているデルファイのバージョンは言うことはありません。
tfilestream.create()コンストラクターにバージョン2007までのバグがあります(少なくとも)。これは、あなたの時折の並行性の問題を説明するかもしれません。
そうは言っても、バグは、予想どおりにファイルが作成されない可能性が高いと思います(シェルモードがさらに指定されている場合)、これは順番に並行性の問題につながる可能性があります。
これを回避する1つの方法は、ファイルを作成する必要がある場合に、最初にファイルを作成してから、別のコンストラクター呼び出しとして書き込むためにそれを開くだけです。
if not FileExists(filename) then
begin
// There may be a more efficient way of creating an empty file, but this
// illustrates the approach
LogFile := TFileStream.Create(FileName, fmCreate);
LogFile.Free;
line := Header + #13#10 + s + #13#10;
end
else
line := s + #13#10;
Logfile:=tfilestream.Create(Filename,fmOpenWrite or fmShareDenyNone);
try
logfile.Seek(0,soFromEnd);
Logfile.Write(line[1], length(line));
finally
Logfile.free;
end;
標準を使用します 追加 ファイルの作成/開くコマンド、使用 write
ログを更新するには close
すぐにファイル。
オペレーティングシステムのジョブを使用して、ファイルをコピー/移動します。それを再試行し、あなたが必要とするものよりも大きな周波数で起動します。
Delphi内からやりたい場合は、使用してください 移動ファイル 全体を動かすために。
あなたはログの書き込みと動きの両方を包みたいかもしれません try-except
したがって、ファイルシステム(Windows上のNTFS?)があなたの同時性を解決しない場合、彼らは妥当な回数を再試行することができます。最悪の場合、どちらも次のとおりです。
- ファイルは移動し、再作成され、書き込みます。
- ファイルは、書かれているため、すぐには移動されません。
OSが人種条件を解決しない場合、セマフォ/ロックを使用して飢えたアクションを優先する必要があります。
「isfileinuse」などの関数を検索するか、次のようなものを使用できると確信しています。
// master
while IsFileInUse(*AFileName*) do
Sleep(10);
write-content-to-file
// slave
while IsFileInUse(*AFileName*) do
Sleep(10);
copy-file-to-a-special-location
そしてプレスト!!あなたは終わった!