3

マスターPCで毎秒情報を毎日のテキストファイルに記録するアプリケーションがあります。同じアプリケーションを使用しているネットワーク上のスレーブPCが、このテキストファイルをローカルドライブにコピーしたいと考えています。ファイルアクセスの問題が発生することがわかります。

これらのファイルは、それぞれ30〜40MB以下である必要があります。ネットワークは100MBのイーサネットになります。コピープロセスに1秒以上かかる可能性があることがわかります。つまり、ログPCは、読み取り中に書き込み用にファイルを開く必要があります。

ファイルの書き込み(ロギング)とファイルのコピーの手順に最適な方法は何ですか?標準のWindowsCopyFile()プロシージャがあることは知っていますが、これによりファイルアクセスの問題が発生しました。fmShareDenyNoneフラグを使用するTFileStreamもありますが、これによってアクセスの問題が発生することもあります(1週間に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;
4

3 に答える 3

2

そもそも共有ファイルを何度も閉じたり開いたりしないことをお勧めします。あなたは毎秒それに書き込むので、それはただ不必要なオーバーヘッドです。

マスター側で、ファイルを作成して閉じ(フラグを他のフラグと一緒に使用することはできません!)、共有モードでfmCreate再度開き、開いたままにして、必要に応じて書き込みます。fmOpenWritefmShareDenyWrite

スレーブ側では、共有fmOpenReadモードでファイルを開き、開いたfmShareDenyNoneままにして、毎秒ファイルから読み取ります。毎回ネットワーク経由で共有ファイル全体をコピーする必要はありません。それは無駄な帯域幅です。過去数秒間に書き込まれた新しいデータを読むだけで、それだけです。スレーブがデータをローカルファイルに保存する必要がある場合は、共有ファイルとは独立して別のローカルファイルを管理し、必要に応じて新しいデータをローカルファイルにプッシュできます。

于 2011-01-14T20:37:21.050 に答える
1

特定の時折発生する問題に対処するには:

使用しているDelphiのバージョンはわかりません。

(少なくとも)バージョン2007までのTFileStream.Create()コンストラクターにはバグがあります。これは、時折発生する同時実行の問題を説明している可能性があります。

そうは言っても、このバグにより、ファイルが期待どおりに作成されない可能性が高くなると思います(ShareModeが追加で指定されている場合)。これにより、同時実行の問題が発生する可能性があります。

これを回避する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;
于 2011-01-14T05:46:53.207 に答える
0

標準の[ファイルの作成/オープンを追加]コマンドを使用し、を使用writeしてログを更新しclose、ファイルをすぐに更新します。

オペレーティングシステムのジョブを使用して、ファイルをコピー/移動します。再試行して、必要な頻度よりも高い頻度で起動してもらいます。

Delphi内から実行する場合は、MoveFileを使用してすべてを移動します。

ファイルシステム(WindowsのNTFS?)で同時実行性が解決されない場合に、ログの書き込みと移動の両方をラップしてtry-except、妥当な回数再試行できるようにすることをお勧めします。最悪の場合、次のいずれかです。

  1. ファイルが移動され、再作成されて書き込まれます。
  2. ファイルは書き込まれているため、すぐには移動されません。

OSが競合状態を解決しない場合は、セマフォ/ロックを使用して飢餓状態のアクションを優先する必要があります。

于 2011-01-14T04:43:59.777 に答える