Delphi 查找文本文件

Delphi 查找文本文件,delphi,text-files,Delphi,Text Files,我正在处理非常大的文本文件,2GB和更多。我想要一个类似Seek()的函数。有人做过这样的事吗?加载到TStringList是不可能的。也可以使用非类型化文件。目前我正在使用readLn,但这会持续太长时间。谢谢。你设置了一些非常严格的边界条件 我唯一能想到的就是尝试从文本文件中获取句柄,并使用win32函数直接搜索。不过要小心文本文件缓存 如果使用writeln/readln的大型代码库是原因,那么实现您自己的文本文件驱动程序(或简化缓存)可能是解决方案 Free Pascal有一个getfi

我正在处理非常大的文本文件,2GB和更多。我想要一个类似Seek()的函数。有人做过这样的事吗?加载到TStringList是不可能的。也可以使用非类型化文件。目前我正在使用readLn,但这会持续太长时间。谢谢。

你设置了一些非常严格的边界条件

我唯一能想到的就是尝试从文本文件中获取句柄,并使用win32函数直接搜索。不过要小心文本文件缓存

如果使用writeln/readln的大型代码库是原因,那么实现您自己的文本文件驱动程序(或简化缓存)可能是解决方案


Free Pascal有一个getfilehandle函数,用于从textfile/tfilerec文件检索操作系统句柄。我不知道最近的Delphi在这个部门增加了什么。

将文件逐段映射到内存(CreateFileMapping/MapViewOfFile),然后扫描映射的内存并建立索引-每行开头的位置列表。然后,将通过获取文件中第n行的位置并搜索到此位置来执行搜索操作。然后使用TFileStream对文件执行随机访问,或者,如果您只读取文件,也可以使用文件映射进行随机访问-这可能比使用TFileStream与文件映射并行使用还要快

如果您需要行级粒度而不是字节级粒度,则绝对无法避免至少读取整个文件一次以查找行结束标记(LF或CRLF,取决于您的环境)。这是一个硬限制-您无法提前知道行结束位置

在构建行尾到字节的偏移量索引后,您可以将其缓存在磁盘上,并使用启发式的“上次修改时间”来检查是否需要重新生成索引(您需要一种启发式方法,因为您无法确保文件内容没有更改,除非通过读取它,然后您还可以重建索引,因为您将受到I/O限制。)

正如其他人所建议的,底层机制必须是CreateFileMapping/CreateViewOfFile(或POSIX下的mmap)。

试试看

封装Windows文件处理例程,允许处理大于2GB的文件

包括对非缓冲访问(文件\u标志\u无\u缓冲)和顺序访问文件的缓冲的支持。还包括流包装类


您可以使用此功能更改TText文件中的当前位置:

function TextSeek(var f: Text; position: Int64): boolean;
var pos64: Int64Rec absolute position;
    resHi: cardinal;
begin
  result := false;
  with TTextRec(f) do
  begin
    if mode<>fmInput then
      exit;
    resHi := pos64.Hi;
    if (SetFilePointer(handle,pos64.Lo,@resHi,FILE_BEGIN)<>pos64.Lo) or
       (resHi<>pos64.Hi) then
      exit;
    BufEnd := 0; // flush internal reading buffer
    BufPos := 0;
    result := true; // success
  end;
end;
函数TextSeek(变量f:Text;位置:Int64):布尔;
var pos64:Int64Rec绝对位置;
雷希:红衣主教;
开始
结果:=假;
带TTextRec(f)do
开始
如果是MODEFM输入,则
出口
resHi:=pos64.Hi;
如果(SetFilePointer(handle,pos64.Lo,@resHi,FILE_BEGIN)pos64.Lo)或
(你好)那么
出口
BufEnd:=0;//刷新内部读取缓冲区
BufPos:=0;
结果:=true;//成功
结束;
结束;
成功时返回true,错误时返回false(未打开文件的无效位置)


如果希望快速访问,请确保已手动设置{$I-}并检查IOResult,并且已使用一些缓冲区调用System.SetTextBuffer()(1KB到64KB可能有意义).

我不清楚seek函数应该做什么,查找字节中的特定偏移量?查找行号?还是什么?当在内存中加载2,5 GB时,我按页加载,一次加载300000行。我创建索引并移动到下一页。但这只给了我顺序访问,我希望直接访问。对于如此巨大的数据文件,因为内存映射的文件不总是有效的-所以按页加载是最好的方法。为什么这会给你顺序访问?你有一个索引。使用索引定义的查找位置。将文件映射到内存如何帮助初始扫描?我怀疑它比逐块顺序读取更快(即:设置一个缓冲区,该缓冲区是文件系统块大小的倍数,并读取该缓冲区)@Cosmin的操作少一点-使用MapViewOfFile,您可以得到一个指针,可以立即传递到某个地方。使用ReadFile,您有一个缓冲区,可以传递给ReadFile API,后者调用NtReadFile,后者调用ZhreadFile,后者发出一个IRP,该IRP可以遍历整个驱动程序堆栈。差别很小,但它仍然存在。@Cosmin:MMF很大比文件I/O更快,尤其是顺序块读取。在我自己的一个应用程序中,当使用这两种技术读取多GB文件时,MMF可以在一分钟内完成,而文件I/O可能需要几分钟。-1因为内存映射在某些情况下无法处理如此大的文件。或者,您必须关闭当前的MapViewOfFile,然后重新打开这是一个MB大小的“窗口”。所以这不是一个比顺序解决方案更好的解决方案。@a.Bouchez你看到“逐块”这个短语了吗?