如何在C#中清空/刷新Windows READ磁盘缓存?

如果我试图确定驱动器的读取速度,我可以编写例程来将文件写入文件系统,然后再读取这些文件。 不幸的是,由于Windows执行磁盘读取缓存,因此无法提供准确的读取速度。

有没有办法在C#/ .Net(或者可能使用Win32 API调用)中刷新驱动器的磁盘读取缓存,以便我可以直接从驱动器读取文件而不缓存它们?

为何选择DIY?

如果您只需确定驱动器速度并且对学习如何从.NET刷新I / O缓冲区不感兴趣,则可以使用http://research.microsoft.com/barc/Sequential_IO/中的 DiskSpd实用程序。 它具有随机/顺序模式,有和没有缓冲区刷新。

该页面还包含一些您可能觉得有用的I / O相关研究报告。

康斯坦丁:谢谢! 该链接有一个命令行EXE,它执行我正在寻找的测试。

我还在该页面上找到了一个链接到该页面上更有趣的文章(在Word和PDF中): 使用.NET的顺序文件编程模式和性能

在本文中,它讨论了未缓冲的文件性能(低,没有读/写缓存 – 只是原始磁盘性能。)

引自文章:

在V2 .NET框架中没有简单的方法来禁用FileStream缓冲。 必须直接调用Windows文件系统以获取未缓冲的文件句柄,然后在C#中将结果“包装”在FileStream中,如下所示:

[DllImport("kernel32", SetLastError=true)] static extern unsafe SafeFileHandle CreateFile( string FileName, // file name uint DesiredAccess, // access mode uint ShareMode, // share mode IntPtr SecurityAttributes, // Security Attr uint CreationDisposition, // how to create uint FlagsAndAttributes, // file attributes SafeFileHandle hTemplate // template file ); SafeFileHandle handle = CreateFile(FileName, FileAccess.Read, FileShare.None, IntPtr.Zero, FileMode.Open, FILE_FLAG_NO_BUFFERING, null); FileStream stream = new FileStream(handle, FileAccess.Read, true, 4096); 

使用FILE_FLAG_NO_BUFFERING标志调用CreateFile()会告诉文件系统绕过该文件的所有软件内存缓存。 作为FileStream构造函数的第三个参数传递的’true’值表示流应该取得文件句柄的所有权,这意味着当流关闭时文件句柄将自动关闭。 在这个hocus-pocus之后,以与任何其他方式相同的方式读取和写入未缓冲的文件流。

Fix的响应几乎正确且优于PInvoke。 但它有错误 ,不起作用……

要打开没有缓存的文件,需要执行以下操作:

 const FileOptions FileFlagNoBuffering = (FileOptions)0x20000000; FileStream file = new FileStream(fileName, fileMode, fileAccess, fileShare, blockSize, FileFlagNoBuffering | FileOptions.WriteThrough | fileOptions); 

几条规则:

  1. blockSize必须是硬盘驱动器簇大小对齐(大多数时间为4096)
  2. 文件位置更改必须是群集大小对齐
  3. 你不能读/写少于blockSize或阻止不对齐它的大小

并且不要忘记 – 还有HDD缓存(比缓存更慢和更小),你无法关闭它(但有时FileOptions.WriteThrough有助于不缓存写入)。 使用这些选项,您没有理由进行刷新,但请确保您已经正确测试了这种方法在缓存执行速度较慢的情况下不会减慢速度。

 const int FILE_FLAG_NO_BUFFERING = 0x20000000; return new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read,64 * 1024, (FileOptions)FILE_FLAG_NO_BUFFERING | FileOptions.Asynchronous & FileOptions.SequentialScan); 

我发现这篇文章似乎这是一个复杂的程序,因为你还必须刷新其他缓存。