TStreamWriter 锁定文件以供读取

TStreamWriter locks file for Read

在我们的项目中,我们使用 StreamWriter 写入日志文件。

在写作时,我想在文件中搜索一些特定的行。例如。在单元测试期间。但不知何故我无法从文件中读取,因为它被进程阻止了。我不明白为什么它被阻止,因为我认为我打开 FileStream 没有任何阻塞。

我将项目中的所有内容提取到这个小示例中。 我必须更改什么才能在写入文件时不阻止文件读取?

program Playground;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils, System.Classes;

var
  FileStream: TFileStream;
  FileStreamWriter : TStreamWriter;
  strList: TStringList;
  fileName: String;

begin
  try
    strList := TStringList.Create;
    fileName := 'TestFile.txt';

    FileStream := TFileStream.Create(fileName, fmCreate or fmShareDenyNone);
    FileStreamWriter := TStreamWriter.Create(FileStream, TEncoding.Unicode);
    FileStreamWriter.WriteLine('12345');
    strList.LoadFromFile(fileName); // Crashes because a proccess blocks the file

    strList.Free;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;

  Readln;
end.

正如 Peter Wolf 在他的评论中所说,您遇到问题的原因不在于您的代码,而在于 StringList.LoadFromFile 代码。

您会看到,当字符串列表尝试加载文件内容时,它打开文件的方式会阻止其他应用程序读取其内容。

下面是 StringList.LoadFromFile 代码的样子:

procedure TStrings.LoadFromFile(const FileName: string);
var
  Stream: TStream;
begin
  Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
  try
    LoadFromStream(Stream);
  finally
    Stream.Free;
  end;
end;

因此,为了避免此问题,您应该自己创建另一个文件流,而不是使用该文件流将文件内容读入 StringList

program Playground;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils, System.Classes;

var
  FileStream: TFileStream;
  StrListFS: TFileStream;
  FileStreamWriter : TStreamWriter;
  strList: TStringList;
  fileName: String;

begin
  try
    strList := TStringList.Create;
    fileName := 'D:\TestFile.txt';

    FileStream := TFileStream.Create(fileName, fmCreate or fmShareDenyNone);
    FileStreamWriter := TStreamWriter.Create(FileStream, TEncoding.Unicode);
    FileStreamWriter.WriteLine('12345');
    //strList.LoadFromFile(fileName); // Crashes because a proccess blocks the file

    //Create a new file stream that we will use for reading the file contents into
    //our string list.
    StrListFS := TFileStream.Create(fileName, fmOpenRead or fmShareDenyNone);
    //Load contets from a file into a stream by using our newly created FileStream
    strList.LoadFromStream(StrListFS);
    //Free the file stream when we are done loading the data.
    StrListFS.Free;

    strList.Free;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;

  Readln;
end.

理论上,您可以使用流编写器使用的相同文件流将该文件的内容读入字符串列表,但请注意,这样做会改变您的流位置,因此您必须先保存之前的位置并在将文件内容读入字符串列表后恢复它。

即使您以锁定模式打开流写入器文件流,这种方式也可以做到这一点,这会阻止多个文件打开 processes/handles。