我在与巨大的固定长度记录数据文件交互时遇到了问题。 文件大小超过 14 GB。 当我看到 System.Filesize()
函数的返回值远小于大文件中的实际记录数时,我第一次注意到一个问题,考虑到文件中的字节数和每条记录的长度。 (System.Filesize 返回给定Reset()
调用期间指定的记录大小的非类型化文件中的记录数。 它不返回文件中的字节数)。 我将其归结为返回类型,System.Filesize()
是Longint而不是Int64。
我通过调用GetFileSizeEx()
并自己计算记录数来解决最初的问题。 遗憾的是,当尝试访问偏移量深入文件的文件中的记录时,BlockRead()
也会失败。 我猜再次使用了代码中某处溢出的值。
是否有Delphi 6的替代模块可以处理大文件,并且可以替代系统单元文件I/O调用? 如果可以的话,我尽量避免自己滚动。
您可以使用Primoz Gabrijelcic的GpHugeFile
。我自己使用这个库从Delphi 7访问更大的文件(>2GB)。无论如何,在您的情况下,您必须考虑尝试更改应用程序逻辑并迁移到数据库方案,该方案比基于记录文件的方案更有效。
试试 TGpHugeFile。
事实证明,由于使用了低容量数值类型,系统单元使用的内部查找例程也存在问题。 我编写了自己对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;
你不能将Pascal I/O用于这样的大文件,而不是在任何版本的Delphi中。最好的办法是使用没有此类限制的TFileStream
。