我遇到了与巨大的固定长度记录数据文件交互的问题。该文件大小超过14 GB。我首先注意到一个问题,当我看到System.Filesize()
函数的返回值远远小于大文件中的实际记录数时,给定文件中的字节数和每个记录的长度。 (给定在Reset()
调用期间指定的记录大小,System.Filesize返回无类型文件中的记录数。它不返回文件中的字节数)。我将它归结为返回类型System.Filesize()
是Longint而不是Int64。
我通过调用GetFileSizeEx()
并自己计算记录数来解决最初的问题。不幸的是,BlockRead()
在尝试访问文件中偏移深入文件的记录时也会失败。我猜再次使用的值正在代码中的某处溢出。
Delphi 6是否有可以处理大文件的替换模块,可替代系统单元文件I / O调用?如果可以的话,我试图避免自己动手。
答案 0 :(得分:6)
您可以使用GpHugeFile
中的Primoz Gabrijelcic。我自己使用这个库从Delphi 7访问更大的文件(> 2gb)。无论如何,在你的情况下,你必须考虑尝试改变你的app逻辑并迁移到数据库方案,这对于基于记录文件的方案来说效率要高得多。
答案 1 :(得分:2)
尝试TGpHugeFile。
答案 2 :(得分:2)
事实证明,由于使用低容量数字类型,系统单元使用的内部搜索例程也存在问题。我编写了自己对Windows SetFilePointerEx()函数的调用,一切都很顺利。我已经提供了下面的源代码,以防它可以帮助其他人。我已经包含了我创建的代码以正确获取记录数量,因为您需要两者。其他一切都是一样的。
// Some constants
const
kernel = 'kernel32.dll';
function SetFilePointerEx(hFile: Integer; distanceToMove: Int64; var newFilePointer: Int64; moveMethod: DWORD): boolean; stdcall; external kernel name 'SetFilePointerEx';
// easyGetFileSize() is a replacement filesize function. Use it to get the number of bytes in the huge file. To get the number of records just "div" it by the record size.
function GetFileSizeEx(hFile: THandle; var FileSize: Int64): BOOL; stdcall; external 'kernel32.dll' name 'GetFileSizeEx';
function easyGetFileSize(theFileHandle: THandle): Int64;
begin
if not GetFileSizeEx(theFileHandle, Result) then
RaiseLastOSError;
end;
// ---- Replacement seek function. Use this instead.
procedure mySeek(var f: File; recordSize, recNum: Int64);
var
offsetInBytes, numBytesRead: Int64;
pBigInt: ^Int64;
begin
offsetInBytes := recNum * recordSize;
pBigInt := nil; // Not interested in receiving a new pointer after seek.
// Call the Windows seek call since Delphi 6 has problems with huge files.
if not SetFilePointerEx(TFileRec(f).Handle, offsetInBytes, pBigInt^, FILE_BEGIN) then
raise Exception.Create(
'(mySeek) Seek to record number # '
+ IntToStr(recNum)
+ ' failed');
end;
答案 3 :(得分:1)
你不能在这样的大文件中使用Pascal I / O,不能在任何版本的Delphi中使用。您最好的选择是使用没有此类限制的TFileStream
。