Delphi TStreamReader - 如何在可共享模式下读取?

use*_*073 2 delphi

我在Delphi Tokyo编写了一个例程,它接受多个文件(例如CSV)并将它们合并在一起,让用户可以忽略除第一行之外的所有文件的第一行(因为CSV文件通常有标题行/列名)在合并文件时,我只想要一个标题的副本).我遇到的问题是,即使我只读取各种输入文件,如果文件在另一个进程中打开(特别是Excel),我的应用程序会出错:"无法打开文件.进程无法访问该文件,因为它被另一个进程使用."

我正在使用TStreamReader.如何告诉TStreamReader它应该以只读方式打开文件...并且即使文件在其他地方打开也继续?

代码如下:

procedure glib_MergeTextFiles(const InFileNames: array of string; const OutFileName: string;
          HasHeader: Boolean = True;
          KeepHeader: Boolean = True);
var
  I: Integer;
  InStream: TStreamReader;
  OutStream: TStreamWriter;
  Line: string;
  IsFirstLine: Boolean;
begin
  // Create our output stream
  OutStream := TStreamWriter.Create(OutFileName, False, TEncoding.UTF8);
  try
    for I := 0 to high(InFileNames) do
    begin
      InStream := TStreamReader.Create(InFileNames[I], TEncoding.UTF8);
      IsFirstLine := True;
      try
        while not InStream.EndOfStream do
        begin
          Line := InStream.ReadLine;

          if IsFirstLine then { First Line }
          begin
            if HasHeader = False then
            begin
              OutStream.WriteLine(Line);
            end
            else
            begin
              // Is First Line, Has Header
              if I = 0 then  {is first file}
                OutStream.WriteLine(Line);
            end;
          end
          else
          begin
            OutStream.WriteLine(Line);
          end;

          IsFirstLine := False;
        end;

      finally
        InStream.Free;
      end;

    end;
  finally
    OutStream.Free;
  end;
end;
Run Code Online (Sandbox Code Playgroud)

Ser*_*yuz 5

问题在于共享模式.默认情况下,流阅读器会创建一个文件流以供只读,但不指定共享模式,因此它会打开文件以进行独占访问.但是,要在已在其他位置打开文件时打开文件进行读取,必须先使用该FILE_SHARE_READ标志打开该文件以共享读取权限:

FILE_SHARE_READ
0x00000001

在文件或设备上启用后续打开操作以请求读取访问权限.

否则,如果其他进程请求读取访问权限,则无法打开该文件或设备.

如果未指定此标志,但已打开文件或设备以进行读取访问,则该函数将失败.

您可以将自己的文件流传递给流阅读器,使用您喜欢的模式打开:

var
  I: Integer;
  FileStream: TFileStream;
  InStream: TStreamReader;
  ..
begin
...
  FileStream := TFileStream.Create(InFileNames[I], fmOpenRead or fmShareDenyNone);
  try
    InStream := TStreamReader.Create(FileStream, TEncoding.UTF8);
    try
      ..
Run Code Online (Sandbox Code Playgroud)

同样,这需要Excel在打开文件时执行相同操作,但是通过我的简单测试,它看起来就像它一样.