我正在处理非常大的文本文件,2GB甚至更多。我想有一个类似Seek()的函数。有没有人这样做过?加载到TStringList是不可能的。也使用无类型文件。现在我正在使用readLn,但这持续时间过长。感谢。
答案 0 :(得分:13)
将文件按片段映射到内存(CreateFileMapping / MapViewOfFile),然后扫描映射的内存并构建索引 - 每行开始的位置列表。然后通过获取文件中第N行的位置并寻找此位置来执行搜索操作。然后使用TFileStream对文件执行随机访问,或者,如果您只读取文件,则可以使用文件映射进行随机访问 - 这可能比使用TFileStream并行文件映射更快。
答案 1 :(得分:3)
尝试GpHugeFile。
封装Windows文件处理例程,允许使用> 2GB文件。
包括支持非缓冲访问(FILE_FLAG_NO_BUFFERING)和缓冲顺序访问的文件。还包括流包装类。
答案 2 :(得分:2)
你设置了一些相当难的边界条件。
我唯一可以想象的是尝试从文本文件中获取句柄,并使用win32函数直接搜索。请注意文本文件缓存。
如果使用writeln / readln的大型代码库是原因,那么实现自己的文本文件驱动程序(或简化缓存)可能就是解决方案。
Free Pascal有一个用于此目的的getfilehandle函数,用于从textfile / tfilerec文件中检索OS句柄。我不知道最近Delphi在这个部门的添加内容。
答案 3 :(得分:2)
如果您需要行级粒度而不是字节级,则绝对无法避免至少读取整个文件一次以找到行标记的结尾(LF或CRLF,具体取决于您的环境)。 )这是一个硬限制 - 你无法事先知道你的终点将会是什么。
在构建行结束到字节偏移量索引之后,您可以将其缓存在磁盘上并使用启发式“la last last time”来检查索引是否需要重新生成(您需要启发式,因为您可以'确保文件内容没有改变,除非通过阅读它,然后你也可以重建索引,因为你仍然会受到I / O限制。)
正如其他人所建议的那样,底层机制必须是CreateFileMapping / CreateViewOfFile(或POSIX下的mmap)。
答案 4 :(得分:1)
您可以使用此功能更改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;
成功时返回true,错误时返回false(未打开文件的无效位置)。
如果您想要快速访问,请确保已设置{$ I-}并手动检查IOResult,并使用一些缓冲区调用System.SetTextBuffer()(1 KB到64 KB可能有意义)。