我需要直接从驱动器读取文件而不需要任何系统缓冲。我在这里尝试了这段代码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 :(得分:3)
FILE_FLAG_NO_BUFFERING
对文件句柄的使用提出了特殊要求,这些要求与Delphi的THandleStream
类的所有功能都不兼容。主要的这种要求是所有访问都是一致的。这意味着文件指针总是放在扇区边界上,并且所有读取和写入都是扇区大小的倍数。这里的具体失败点是Size
属性。
您正在读取的文件大小不是扇区大小的精确倍数。当您提供的文件大小不是扇区大小的精确倍数时,您引用的答案将失败并显示您报告的错误。据推测,该代码的作者并未意识到这个问题,并且纯粹的机会使用了一个文件,其大小是扇区大小的精确倍数。
您可以通过使用大小为4096的精确倍数的输入文件执行代码来确认所有这些。
您可以使用THandleStream
这样的文件句柄,但您需要小心。显然你必须避免Size
。您必须遵守对齐要求。在文件末尾读取时需要小心,因为即使您知道逻辑文件在扇区结束之前结束,您也需要读取整个扇区。这意味着使用Read
而不是ReadBuffer
。
坦率地说,在我看来,如果你必须使用无缓冲的文件访问,那么我不相信流抽象是一个很好的选择。我会直接使用Windows API。