2011-05-18 83 views
3

我遇到了與巨大的固定長度記錄數據文件交互的問題。該文件大小超過14 GB。考慮到文件中的字節數和每條記錄的長度,當我看到System.Filesize()函數的返回值遠遠小於大文件中的實際記錄數時,我首先注意到了一個問題。 (System.Filesize返回在Reset()調用期間指定的記錄大小的非類型化文件中的記錄數,它不會返回文件中的字節數)。我把它歸類爲返回類型System.Filesize()是Longint而不是Int64。對Delphi 6的巨大文件支持? (替換系統模塊?)

我通過調用GetFileSizeEx()並計算自己的記錄數來解決最初的問題。不幸的是,BlockRead()在嘗試訪問文件中偏移量很深的文件中的記錄時也失敗。我猜測再次有代碼中某處溢出的值被使用。

是否有替代模塊用於Delphi 6那裏可以處理大文件並且是系統單元文件I/O調用的替代品?如果可以的話,我儘量避免自己滾動。

+3

14 gb您必須考慮使用數據庫來代替。 – RRUZ 2011-05-18 21:46:14

+0

也有流訪問文件。但我不記得他們是否支持> 2GB的文件。 – CodesInChaos 2011-05-18 21:52:50

+0

Streams支持超過十年的大文件,@Code。參見'TStream',它的兩個僞抽象實現'Seek'。 – 2011-05-18 22:03:18

回答

6

您可以使用Primoz GabrijelcicGpHugeFile。我自己使用這個庫來從Delphi 7訪問更大的文件(> 2GB)。無論如何,對於你的情況,你必須考慮嘗試改變你的應用程序邏輯,並遷移到一個更有效的數據庫方案,這是一個基於記錄文件的方案。

+2

效率如何?在不知道記錄結構的情況下,我們無法知道數據庫是否更具空間效率。而對於固定大小的記錄,尋找和遍歷文件的時間效率不會比數據庫低。 – 2011-05-18 22:03:41

+1

@Rob,必須存在一些使用記錄文件系統更有效(例如少量記錄)使用數據庫的情況。但在大多數情況下(並且在這14GB的數據中),RDBMS系統是更好的性能選擇。 – RRUZ 2011-05-18 22:09:55

+2

我不明白什麼是內建的流類,導致你推薦這個第三方代碼有什麼問題。 – 2011-05-18 22:24:03

1

你不能在這種龐大的文件中使用Pascal I/O,而不是在任何版本的Delphi中使用。你最好的選擇是使用TFileStream,它沒有這樣的限制。

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; 
+2

這只是拖延不可避免的。您應該停止使用Pascal本機I/O並開始使用TFileStream。 – 2011-05-19 13:53:09