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

时间:2018-12-17 17:03:35

标签: 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;

1 个答案:

答案 0 :(得分: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
      ..

同样,这要求Excel在打开文件时执行相同的操作,但是通过我的简单测试,它看起来确实如此。