我有一个应用程序将信息记录到主电脑上每秒的每日文本文件。使用同一应用程序网络上的从属电脑希望将此文本文件复制到其本地驱动器。我可以看到将会有文件访问问题。

这些文件应不得大于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 分享,打开它,并每秒从中阅读。无需每次通过网络复制整个共享文件。那是浪费的带宽。只需阅读过去几秒钟中编写的任何新数据,仅此而已。如果从属需要将数据存储在本地文件中,则可以独立于共享文件的单独的本地文件,在需要时将新数据推入本地文件。

其他提示

处理您的特定偶尔经常性问题:

您不会说您正在使用哪种版本的Delphi。

tfileStream.create()构造函数(至少)(至少)(至少)都有一个错误。这可能解释了您偶尔的并发问题。

话虽如此,我相信该错误更有可能导致未按预期创建文件(另外指定了ShareMode),这可能会导致您的并发问题。

解决此问题的一种方法是,当需要创建文件时,首先创建文件,然后将其作为单独的构造函数打开以作为单独的构造函数打开 - 这实际上使文件创建是单独的一步,而文件编写过程的一致部分:

  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上的NTF?)无法解决您的并发性,则可以将它们重试。在最坏的情况下,要么是:

  1. 该文件被移动了,并将其重新创建并写入。
  2. 该文件不会立即移动,因为它被写入。

如果操作系统无法解决比赛条件,则必须使用信号量/锁定饥饿的动作优先考虑。

搜索称为“ 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

和Presto!你完成了!!

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top