【问题标题】:Delphi writing to a network share using TFilestream locks the file when network is lostDelphi 使用 TFilestream 写入网络共享会在网络丢失时锁定文件
【发布时间】:2012-08-23 03:45:25
【问题描述】:

我正在尝试使用 TFilestream 写入网络共享(本地)。如果网络连接不中断,一切正常。

但是,如果我拔掉网线然后重新连接,由于访问限制,后续打开文件流的尝试会失败。我什至无法删除资源管理器中的文件!似乎 TFilestream 锁定了文件,解决此问题的唯一方法是重新启动。

在我的应用程序中,我在写入文件的整个过程中都保持文件打开(这是一个每秒写入一次的日志文件)。

我失败的代码如下:

procedure TFileLogger.SetLogFilename(const Value: String);
var line : String;
Created : Boolean;
begin
  if not DirectoryExists(ExtractFilePath(Value)) then //create the dir if it doesnt exist
  begin
       try
         ForceDirectories(ExtractFilePath(Value));
       except
         ErrorMessage(Value); //dont have access to the dir so flag an error
         Exit;
       end;
  end;
  if Value <> FLogFilename then //Either create or open existing
  begin
      Created := False;          
      if Assigned(FStream) then
         FreeandNil(FStream);
      if not FileExists(Value) then   //create the file and write header
      begin
           //now create a new file
           try
              FStream := TFileStream.Create(Value,fmCreate);
              Created := True;
           finally
             FreeAndNil(FStream);
           end;
           if not Created then //an issue with creating the file
           begin
                ErrorMessage(Value);
                Exit;
           end;
           FLogFilename := Value;
           //now open file for writing
           FStream := TFileStream.Create(FLogFilename,fmOpenWrite or fmShareDenyWrite);
           try
              line := FHeader + #13#10;
              FStream.Seek(0,soFromEnd);
              FStream.Write(Line[1], length(Line));
              FSuppress := False;
           except
              ErrorMessage(Value);  
           end;
      end else begin //just open it
           FLogFilename := Value;
           //now open file for writing
           FStream := TFileStream.Create(FLogFilename,fmOpenWrite or fmShareDenyWrite); //This line fails if the network is lost and then reconnected
      end;
  end;
end;

如果有人有任何建议,将不胜感激。

【问题讨论】:

  • 这真的是 TFileStream 的问题吗?如果是这样,那么就使用其他东西,比如 CreateFile。

标签: delphi logging filestream file-locking


【解决方案1】:

尝试使用Network Share API 关闭文件,即NetFileEnumNetFileClose 函数。另见a related question

【讨论】:

    【解决方案2】:

    我做了类似的事情,但不要使用TFileStream。我使用来自SysUtils 的文件方法。这基本上是我所做的,适合您的情况:

    // variables used in pseudo-code below
    var
      fHandle, bytesWriten: Integer;
      Value: string;
    
    • 使用fHandle := FileOpen('filename', fmOpenReadWrite or ...)打开输出文件。
    • 验证是fHandle &gt; -1,如果不是则休眠并循环。
    • 写输出bytesWritten := FileWrite(fHandle, Value, Length(Value));
    • 检查bytesWritten,他们应该= Length(Value)
    • 如果bytesWritten0,您就知道文件句柄丢失了。我在我的所有代码周围放置了一个try ... finally 块并执行if fHandle &gt; -1 then try FileClose(fHandle); except end;,以便它强制系统释放文件句柄,即使该文件不再可访问。
    • 如果 bytesWritten0,则休眠几秒钟,然后重试。

    在添加代码之前,我似乎遇到了与您描述的类似的问题:

    if fHandle > -1 then
      try
        FileClose(fHandle);
      except
      end;
    

    我已使用这种方法将千兆字节文件复制到远程(慢速)网络共享,并且网络共享在复制过程中丢失了几次。一旦网络共享再次可用,我就可以恢复复制。您应该能够对您的日志文件执行类似的操作...

    【讨论】:

    • 这不是答案。如果网络再也回不来怎么办?现在你的程序挂在一个繁忙的循环中。 FWIW 无需使用老式的文件 API,可以使用 TFileStream 轻松编写代码。
    • 我从中设计的代码有一个最大的重试次数,这样它就不会被锁定在一个繁忙的循环中;这很容易添加。我不知道 TFileStream 和老式文件 API 是否以不同的方式处理事情,以及这是否可能是问题的一部分。因为我知道它适用于文件 API,所以我想让 Simon 知道该选项是如何工作的......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-10
    相关资源
    最近更新 更多