3

巨大な固定長のレコード データ ファイルを操作する際に問題が発生しています。ファイルのサイズは 14 GB を超えています。System.Filesize()ファイル内のバイト数と各レコードの長さを考えると、関数からの戻り値が巨大なファイル内の実際のレコード数よりもはるかに少ないのを見て、最初に問題に気付きました。(System.Filesize は、呼び出し中に指定されたレコード サイズを指定すると、型指定されていないファイル内のレコード数を返しますReset()。ファイル内のバイト数は返しません)。System.Filesize()Int64 ではなく、倍長整数の戻り値の型までチョークで書きました。

GetFileSizeEx()自分でレコード数を呼び出して計算することで、最初の問題を回避しました。残念ながら、BlockRead()オフセットがファイルの奥深くにあるファイル内のレコードにアクセスしようとすると失敗します。コードのどこかでオーバーフローしている値が使用されていると思います。

巨大なファイルを処理でき、システム ユニットのファイル I/O 呼び出しに代わる Delphi 6 の代替モジュールはありますか? できれば自分で転がすのを避けようとしています。

4

4 に答える 4

6

PrimozGabrijelcicGpHugeFileから使用できます。私はこのライブラリを自分で使用して、Delphi 7からより大きなファイル(> 2GB)にアクセスしました。とにかく、アプリロジックを変更して、レコードファイルに基づくスキームよりもはるかに効率的なデータベーススキームに移行することを検討する必要があります。

于 2011-05-18T21:57:38.503 に答える
2

System ユニットが使用する内部シーク ルーチンにも、容量の小さい数値型が使用されているために問題があったことが判明しました。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;
于 2011-05-18T22:18:24.407 に答える
2

TGpHugeFileを試してください。

于 2011-05-18T22:01:25.967 に答える
1

Delphiのどのバージョンでも、このような巨大なファイルでPascal I/Oを使用することはできません。あなたの最善の策は、TFileStreamそのような制限のないを使用することです。

于 2011-05-18T21:59:30.210 に答える