“扩展内存流时内存不足”

时间:2016-08-12 12:01:02

标签: delphi file-handling

我需要直接从驱动器读取文件而不需要任何系统缓冲。我在这里尝试了这段代码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;

1 个答案:

答案 0 :(得分:3)

FILE_FLAG_NO_BUFFERING对文件句柄的使用提出了特殊要求,这些要求与Delphi的THandleStream类的所有功能都不兼容。主要的这种要求是所有访问都是一致的。这意味着文件指针总是放在扇区边界上,并且所有读取和写入都是扇区大小的倍数。这里的具体失败点是Size属性。

您正在读取的文件大小不是扇区大小的精确倍数。当您提供的文件大小不是扇区大小的精确倍数时,您引用的答案将失败并显示您报告的错误。据推测,该代码的作者并未意识到这个问题,并且纯粹的机会使用了一个文件,其大小是扇区大小的精确倍数。

您可以通过使用大小为4096的精确倍数的输入文件执行代码来确认所有这些。

您可以使用THandleStream这样的文件句柄,但您需要小心。显然你必须避免Size。您必须遵守对齐要求。在文件末尾读取时需要小心,因为即使您知道逻辑文件在扇区结束之前结束,您也需要读取整个扇区。这意味着使用Read而不是ReadBuffer

坦率地说,在我看来,如果你必须使用无缓冲的文件访问,那么我不相信流抽象是一个很好的选择。我会直接使用Windows API。