如何从缓存中卸载文件?

时间:2022-03-22 13:55:19

Anybody knows how to unload a file from cache? I write a file to disk, then I want to read it back. However, Windows is giving me the file from cache.

有谁知道如何从缓存中卸载文件?我写了一个文件到磁盘,然后我想读回来。但是,Windows正在从缓存中提供该文件。

begin
...

 {-- Write file --}
 AssignFile(F, FileName);
 Rewrite(F, 1);
 BlockWrite(F, Buf[0], Chunk);
 CloseFile(F);             { FLUSH }

some code...
then.....

 {-- Read file --}
 AssignFile(F, FileName);
 Reset(F, 1);                                                              
 BlockRead(F, Buf[0], Chunk);       <----------- getting file from cache
 CloseFile(F);
end;

- I am trying to determine the write/read speed of a drive.

- 我正在尝试确定驱动器的写入/读取速度。

5 个解决方案

#1


Some code to demonstrate the use of FILE_FLAG_NO_BUFFERING and to test how it affects your reading time:

一些代码演示了如何使用FILE_FLAG_NO_BUFFERING并测试它如何影响您的阅读时间:

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;

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

    finally
      DestStream.Free;
    end;
  finally
    SrcStream.Free;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  i: integer;
begin
  Button1.Enabled := FALSE;
  try
    Update;
    Memo1.Lines.Clear;
    for i := 1 to 5 do begin
      Memo1.Lines.Add(Format('Time for buffered file read: %.3f s',
        [GetTimeForRead(TRUE)]));
    end;
    for i := 1 to 5 do begin
      Memo1.Lines.Add(Format('Time for unbuffered file read: %.3f s',
        [GetTimeForRead(FALSE)]));
    end;
  finally
    Button1.Enabled := TRUE;
  end;
end;

Running this code with a file of 420 MByte size gives on my system:

在我的系统上运行此代码的大小为420 MBy的文件:

Time for buffered file read: 3,974 s
Time for buffered file read: 0,922 s
Time for buffered file read: 0,937 s
Time for buffered file read: 0,937 s
Time for buffered file read: 0,938 s
Time for unbuffered file read: 3,922 s
Time for unbuffered file read: 4,000 s
Time for unbuffered file read: 4,016 s
Time for unbuffered file read: 4,062 s
Time for unbuffered file read: 3,985 s

缓冲文件读取时间:3,974 s缓冲文件读取时间:0,922 s缓冲文件读取时间:0,937 s缓冲文件读取时间:0,937 s缓冲文件读取时间:0,938 s无缓冲文件读取时间:3,922 s时间无缓冲文件读取:4,000 s无缓冲文件读取时间:4,016 s无缓冲文件读取时间:4,062 s无缓冲文件读取时间:3,985 s

#2


I think that you have misunderstood the concept of flushing a file.

我认为你误解了刷新文件的概念。

Flushing a file does not remove it from the disk cache, it causes the content of the file stream's buffer to be written to the file.

刷新文件不会将其从磁盘缓存中删除,而是会将文件流缓冲区的内容写入文件。

(The stream is automatically flushed when you close it. Opening a file and flushing it without writing anything to it has no effect what so ever.)

(当你关闭它时,流会自动刷新。打开一个文件并刷新它而不写任何东西就没有效果了。)

You can look into the FILE_FLAG_NO_BUFFERING flag for reading the file, but it seems from the documentation that it has no effect on files on a hard drive.

您可以查看FILE_FLAG_NO_BUFFERING标志以读取文件,但从文档中可以看出它对硬盘驱动器上的文件没有影响。

MSDN: CreateFile

#3


You'll need to use the Win32 API directly, specifically CreateFile with the FILE_FLAG_NO_BUFFERING flag. It forces the OS to read from the disk instead of the cache, and has the side effect that it also clears out the cache for that file, so the next read without the flag also hits the disk, though it does read it into the cache then.

您需要直接使用Win32 API,特别是使用FILE_FLAG_NO_BUFFERING标志的CreateFile。它强制操作系统从磁盘而不是缓存中读取,并且副作用是它还清除了该文件的缓存,因此没有该标志的下一次读取也会触及磁盘,尽管它会将其读入缓存然后。

#4


File caching is an OS level operation, so is independent of whether you use Delphi or any other language.

文件缓存是一种操作系统级别的操作,因此与您使用Delphi还是任何其他语言无关。

If you give us some idea of why you want to ensure you are not reading from cache, it may be easier to help.

如果您让我们知道您为什么要确保不从缓存中读取数据,那么可能更容易提供帮助。

#5


The code should be fine, unless you're using invalid values for the Chunk variable. E.g., if chunk = 0 then it won't read any data into the buffer, thus the buffer would keep it's old value. (Which could be the same data you just wrote to disk.)

除非您对Chunk变量使用无效值,否则代码应该没问题。例如,如果chunk = 0则它不会将任何数据读入缓冲区,因此缓冲区将保持其旧值。 (这可能是您刚写入磁盘的相同数据。)

#1


Some code to demonstrate the use of FILE_FLAG_NO_BUFFERING and to test how it affects your reading time:

一些代码演示了如何使用FILE_FLAG_NO_BUFFERING并测试它如何影响您的阅读时间:

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;

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

    finally
      DestStream.Free;
    end;
  finally
    SrcStream.Free;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  i: integer;
begin
  Button1.Enabled := FALSE;
  try
    Update;
    Memo1.Lines.Clear;
    for i := 1 to 5 do begin
      Memo1.Lines.Add(Format('Time for buffered file read: %.3f s',
        [GetTimeForRead(TRUE)]));
    end;
    for i := 1 to 5 do begin
      Memo1.Lines.Add(Format('Time for unbuffered file read: %.3f s',
        [GetTimeForRead(FALSE)]));
    end;
  finally
    Button1.Enabled := TRUE;
  end;
end;

Running this code with a file of 420 MByte size gives on my system:

在我的系统上运行此代码的大小为420 MBy的文件:

Time for buffered file read: 3,974 s
Time for buffered file read: 0,922 s
Time for buffered file read: 0,937 s
Time for buffered file read: 0,937 s
Time for buffered file read: 0,938 s
Time for unbuffered file read: 3,922 s
Time for unbuffered file read: 4,000 s
Time for unbuffered file read: 4,016 s
Time for unbuffered file read: 4,062 s
Time for unbuffered file read: 3,985 s

缓冲文件读取时间:3,974 s缓冲文件读取时间:0,922 s缓冲文件读取时间:0,937 s缓冲文件读取时间:0,937 s缓冲文件读取时间:0,938 s无缓冲文件读取时间:3,922 s时间无缓冲文件读取:4,000 s无缓冲文件读取时间:4,016 s无缓冲文件读取时间:4,062 s无缓冲文件读取时间:3,985 s

#2


I think that you have misunderstood the concept of flushing a file.

我认为你误解了刷新文件的概念。

Flushing a file does not remove it from the disk cache, it causes the content of the file stream's buffer to be written to the file.

刷新文件不会将其从磁盘缓存中删除,而是会将文件流缓冲区的内容写入文件。

(The stream is automatically flushed when you close it. Opening a file and flushing it without writing anything to it has no effect what so ever.)

(当你关闭它时,流会自动刷新。打开一个文件并刷新它而不写任何东西就没有效果了。)

You can look into the FILE_FLAG_NO_BUFFERING flag for reading the file, but it seems from the documentation that it has no effect on files on a hard drive.

您可以查看FILE_FLAG_NO_BUFFERING标志以读取文件,但从文档中可以看出它对硬盘驱动器上的文件没有影响。

MSDN: CreateFile

#3


You'll need to use the Win32 API directly, specifically CreateFile with the FILE_FLAG_NO_BUFFERING flag. It forces the OS to read from the disk instead of the cache, and has the side effect that it also clears out the cache for that file, so the next read without the flag also hits the disk, though it does read it into the cache then.

您需要直接使用Win32 API,特别是使用FILE_FLAG_NO_BUFFERING标志的CreateFile。它强制操作系统从磁盘而不是缓存中读取,并且副作用是它还清除了该文件的缓存,因此没有该标志的下一次读取也会触及磁盘,尽管它会将其读入缓存然后。

#4


File caching is an OS level operation, so is independent of whether you use Delphi or any other language.

文件缓存是一种操作系统级别的操作,因此与您使用Delphi还是任何其他语言无关。

If you give us some idea of why you want to ensure you are not reading from cache, it may be easier to help.

如果您让我们知道您为什么要确保不从缓存中读取数据,那么可能更容易提供帮助。

#5


The code should be fine, unless you're using invalid values for the Chunk variable. E.g., if chunk = 0 then it won't read any data into the buffer, thus the buffer would keep it's old value. (Which could be the same data you just wrote to disk.)

除非您对Chunk变量使用无效值,否则代码应该没问题。例如,如果chunk = 0则它不会将任何数据读入缓冲区,因此缓冲区将保持其旧值。 (这可能是您刚写入磁盘的相同数据。)