【问题标题】:Huge file support for Delphi 6? (replacement for System module?)对 Delphi 6 的巨大文件支持? (更换系统模块?)
【发布时间】:2011-08-28 10:12:44
【问题描述】:

我在与一个巨大的固定长度记录数据文件交互时遇到了问题。该文件的大小超过 14 GB。当我看到 System.Filesize() 函数的返回值远小于大文件中的实际记录数时,我首先注意到一个问题,考虑到文件中的字节数和每条记录的长度。 (给定在Reset() 调用期间指定的记录大小,System.Filesize 返回无类型文件中的记录数。它不返回文件中的字节数)。我将其归结为 System.Filesize() 的返回类型是 Longint 而不是 Int64。

我通过调用GetFileSizeEx() 并自己计算记录数来解决最初的问题。不幸的是,BlockRead() 在尝试访问文件中偏移量在文件深处的记录时也会失败。我猜想再次有正在使用的值在代码中的某处溢出。

那里有可以处理大型文件的 Delphi 6 替代模块,并且可以替代系统单元文件 I/O 调用吗?如果可以的话,我会尽量避免自己动手。

【问题讨论】:

  • 14 gb ¡¡¡ 您必须考虑使用数据库。
  • 也有访问文件的流。但我不记得它们是否支持 >2GB 的文件。
  • Streams 支持大文件已有十多年了,@Code。请参阅 TStream,以及 Seek 的两个伪抽象实现。
  • 我会查看生成 14GB 文件的架构或第三方提供商。除了快速解决方案之外,这里真正的问题是存储/访问数据的方法比使用 14GB 文件要好得多!

标签: delphi int64 large-data


【解决方案1】:

您可以使用Primoz Gabrijelcic 中的GpHugeFile。我自己使用这个库从 Delphi 7 访问更大的文件(> 2gb)。无论如何,在您的情况下,您必须考虑尝试更改您的应用程序逻辑并迁移到数据库方案,该方案比基于记录文件的方案更有效。

【讨论】:

  • 如何更高效?如果不知道记录结构,我们就无法知道数据库是否会更节省空间。使用固定大小的记录,查找和遍历文件的时间效率不会低于数据库。
  • @Rob,必须存在一些使用记录文件系统比使用数据库更有效(例如记录少量记录)的情况。但在大多数情况下(在这 14 GB 的数据中),RDBMS 系统是性能更好的选择。
  • 我不明白内置流类有什么问题导致您推荐此第 3 方代码。
  • @David:你显然不知道 Primoz(@gabr 这里)和他的代码。 OmniXMLOmniThreadLibrary 都是 Delphi 自己的内置功能的极好(和免费)替代品,GpHugeFile(以及 Primoz 提供的其他几个单元)也是如此。
  • @ken 我肯定知道 Primoz,但我仍然没有答案!
【解决方案2】:

试试TGpHugeFile

【讨论】:

    【解决方案3】:

    事实证明,系统单元使用的内部查找例程也由于使用了低容量数字类型而存在问题。我编写了自己对 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 并开始使用 TFileStream。
    【解决方案4】:

    你不能在像这样的大文件中使用 Pascal I/O,在任何版本的 Delphi 中都不能。最好的办法是使用没有此类限制的TFileStream

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-22
      • 1970-01-01
      • 2021-10-20
      • 2013-12-05
      • 2020-09-12
      • 1970-01-01
      相关资源
      最近更新 更多