2016-08-12 158 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。