如何在Delphi中有效地读取许多文件的第一行

我的程序中有一个“查找文件”功能,可以找到我的程序读取的带有.ged后缀的文本文件。我在类似于资源管理器的窗口中显示找到的结果,如下所示: 我使用标准的FindFirst / FindNext方法,这非常有效。上面显示的584个文件可在几秒钟内找到并显示。 我现在要做的是在显示屏上添加两列,显示每个文件中包含的“Source”和“Version”。此信息通常位于每个文件的前10行内,如下所示:
1 SOUR FTM
2 VERS Family Tree Maker (20.0.0.368)
现在我自己解析这个问题没有问题,这不是我要问的问题。 我需要帮助的只是如何最快速地从这些文件加载​​前10行,以便我可以解析它们。 我试图做一个StringList.LoadFromFile,但加载大文件需要花费太多时间,例如1 MB以上的文件。 由于我只需要前10行左右,我最好如何获得它们? 我正在使用Delphi 2009,我的输入文件可能是也可能不是Unicode,所以这需要适用于任何编码。 跟进:谢谢Antonio, 我最终做了这个工作正常:
var
  CurFileStream: TStream;
  Buffer: TBytes;
  Value: string;
  Encoding: TEncoding;

try
  CurFileStream := TFileStream.Create(folder + FileName, fmOpenRead);
  SetLength(Buffer, 256);
  CurFileStream.Read(Buffer[0], 256);
  TEncoding.GetBufferEncoding(Buffer, Encoding);
  Value := Encoding.GetString(Buffer);
  ...
  (parse through Value to get what I want)
  ...
finally
  CurFileStream.Free;
end;
    
已邀请:
使用TFileStream并使用Read方法读取所需的字节数。以下是读取位图信息的示例,该位图信息也存储在文件的开头。 http://www.delphidabbler.com/tips/19     
只需自己打开文件进行块读取(不使用TStringList内置功能),然后读取文件的第一个块,然后就可以将该块加载到带有strings.SetText()的字符串列表中(如果使用块函数) )或者只是strings.LoadFromStream()如果您使用流加载块。 我个人只是使​​用FileRead / FileWrite块函数,并将块加载到缓冲区中。您也可以使用similair winapi函数,但这只是无用的代码。 操作系统以块的形式读取文件,这些块几乎在任何平台/文件系统上都至少有512字节,因此您可以先读取512个字节(并希望您获得所有10行,如果您的行通常足够短,这将是真的)。这(实际上)与读取100或200字节一样快。 然后,如果您注意到您的字符串对象只有少于10行,则只需读取下一个512字节块并尝试再次解析。 (或者只是使用1024,2048等块,在许多系统上它可能会快512块,因为文件系统簇大小通常大于512字节)。 PS。此外,在winapi文件函数(CreateFile等)中使用线程或异步功能,您可以异步加载文件中的数据,而其他应用程序可以正常工作。具体来说,在读取大目录期间,接口不会冻结。 这将使您的信息加载看起来更快,(因为文件列表将直接加载,然后几毫秒后其余信息将出现),而实际上并没有提高实际读取速度。 只有当您尝试过其他方法并且您觉得需要额外的提升时才这样做。     
您可以使用
TStreamReader
从任何
TStream
对象中读取单独的行,例如
TFileStream
。对于更快的文件I / O,您可以使用带有
TCustomMemoryStream
的内存映射视图。     
好的,我删除了我的第一个答案。使用上面的Remy的第一个建议,我再次尝试使用内置的东西。我不喜欢这里是你必须创建和释放两个对象。我想我会创建自己的类来包装它:
var
  fs:TFileStream;
  tr:TTextReader;
  filename:String;
begin
  filename :=  'c:temptextFileUtf8.txt';
  fs := TFileStream.Create(filename, fmOpenRead);
  tr := TStreamReader.Create(fs);
  try
      Memo1.Lines.Add( tr.ReadLine );

  finally
    tr.Free;
    fs.Free;
  end;   
end;
如果有人对我以前在这里所拥有的东西感兴趣,那么就会遇到不使用unicode文件的问题。     
有时候oldschool pascal stylee也不是那么糟糕。 即使非oo文件访问似乎不再受欢迎,
ReadLn(F,xxx)
在像你这样的情况下仍然可以正常工作。 下面的代码将信息(文件名,来源和版本)加载到
TDictionary
中,以便您可以轻松查找,或者您可以在虚拟模式下使用listview,并在
ondata
甚至触发时查看此列表中的内容。 警告:以下代码不适用于unicode。
program Project101;
{$APPTYPE CONSOLE}

uses
  IoUtils, Generics.Collections, SysUtils;

type
  TFileInfo=record
    FileName,
    Source,
    Version:String;
  end;

function LoadFileInfo(var aFileInfo:TFileInfo):Boolean;
var
  F:TextFile;
begin
  Result := False;
  AssignFile(F,aFileInfo.FileName);
  {$I-}
  Reset(F);
  {$I+}
  if IOResult = 0 then
  begin
    ReadLn(F,aFileInfo.Source);
    ReadLn(F,aFileInfo.Version);
    CloseFile(F);
    Exit(True)
  end
  else
    WriteLn('Could not open ', aFileInfo.FileName);
end;

var
  FileInfo:TFileInfo;
  Files:TDictionary<string,TFileInfo>;
  S:String;
begin
  Files := TDictionary<string,TFileInfo>.Create;
  try
    for S in TDirectory.GetFiles('h:WINDOWSsystem32','*.xml') do
    begin
      WriteLn(S);
      FileInfo.FileName := S;
      if LoadFileInfo(FileInfo) then
        Files.Add(S,FileInfo);
    end;

    // showing file information...
    for FileInfo in Files.Values do
      WriteLn(FileInfo.Source, ' ',FileInfo.Version);
  finally
    Files.Free
  end;
  WriteLn;
  WriteLn('Done. Press any key to quit . . .');
  ReadLn;
end.
    

要回复问题请先登录注册