2016-08-12 159 views
0

我需要直接從驅動器讀取文件,而無需任何系統緩衝。我在這裏嘗試了這段代碼How to unload a file from cache?不幸的是,我收到錯誤消息「擴展內存流時內存不足」。它發生在我試過的任何文件中。後來我發現SrcStream.Size的返回值總是-1。所以顯然問題在這裏,問題是爲什麼會發生這種情況?「擴展內存流時內存不足」

uses 
    MMSystem; 

function GetTimeForRead(ABuffered: boolean): single; 
const 
    FileToRead = // name of file with maybe 500 MByte size 
var 
    FlagsAndAttributes: DWORD; 
    FileHandle: THandle; 
    SrcStream, DestStream: TStream; 
    Ticks: DWord; 
begin 
    if ABuffered then FlagsAndAttributes := FILE_ATTRIBUTE_NORMAL 
    else FlagsAndAttributes := FILE_FLAG_NO_BUFFERING; 
    FileHandle := CreateFile(FileToRead, GENERIC_READ, FILE_SHARE_READ, nil,OPEN_EXISTING, FlagsAndAttributes, 0); 
if FileHandle = INVALID_HANDLE_VALUE then 
begin 
    Result := 0.0; 
    exit; 
end; 

SrcStream := THandleStream.Create(FileHandle); 
try 
    DestStream := TMemoryStream.Create; 
    try 
    DestStream.Size := SrcStream.Size; 

    Ticks := timeGetTime; 
    DestStream.CopyFrom(SrcStream, SrcStream.Size); 
    Result := 0.001 * (timeGetTime - Ticks); 

finally 
    DestStream.Free; 
end; 
    finally 
    SrcStream.Free; 
    end; 
end; 
+0

我明白了,問題就在那裏。你可以看到我的手指在哪裏,對嗎? –

+1

隱形手指指向隱形代碼?哇,這個互聯網的東西真的很酷。 –

+0

此錯誤消息不顯示 FlagsAndAttributes:= FILE_ATTRIBUTE_NORMAL 但它總是與 崩潰FlagsAndAttributes:= FILE_FLAG_NO_BUFFERING; –

回答

3

FILE_FLAG_NO_BUFFERING地方上使用的文件句柄的特殊要求,不與德爾福THandleStream類的所有功能兼容。主要的這種要求是所有訪問都是一致的。這意味着文件指針始終放置在扇區邊界上,所有讀取和寫入都是扇區大小的倍數。這裏的具體故障點是Size屬性。

您正在閱讀的文件的大小不是確切的扇區大小的倍數。您提到的答案會失敗,並顯示您提交的文件的大小不是扇區大小的確切倍數時報告的錯誤。據推測該代碼的作者並不知道這個問題,而純粹的機會使用了一個文件,其大小是扇區大小的確切倍數。

您可以通過使用其大小爲4096

的整數倍,您或許可以使用THandleStream這樣的文件句柄但你必須要小心的輸入文件執行的代碼證實了這一切。顯然你必須避免Size。你必須尊重對齊要求。讀取文件末尾時需要小心,因爲即使知道邏輯文件在扇區結束之前結束,也需要讀取整個扇區。這意味着使用Read而不是ReadBuffer

坦率地說,在我看來,如果你必須使用無緩衝文件訪問,那麼我不認爲流抽象是一個很好的選擇。我會直接使用Windows API。