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

Posted

技术标签:

【中文标题】如何在 C# 中清空/刷新 Windows READ 磁盘缓存?【英文标题】:How to empty/flush Windows READ disk cache in C#? 【发布时间】:2010-09-12 10:47:34 【问题描述】:

如果我想确定驱动器的读取速度,我可以编写一个例程来将文件写入文件系统,然后再读回这些文件。不幸的是,这并不能提供准确的读取速度,因为 Windows 会进行磁盘读取缓存。

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

【问题讨论】:

【参考方案1】:

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

我还在该页面上找到了指向该页面上更有趣文章(Word 和 PDF)的链接:Sequential File Programming Patterns and Performance with .NET

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

直接引自文章:

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

    [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);

调用 CreateFile() FILE_FLAG_NO_BUFFERING 标志告诉 绕过所有软件的文件系统 文件的内存缓存。这 “真”值作为第三个传递 FileStream 构造函数的参数 表示流应该采取 文件句柄的所有权,含义 文件句柄将 时自动关闭 流已关闭。在这之后 hocus-pocus,无缓冲文件 流被读取和写入相同 和其他方式一样。

【讨论】:

我投了赞成票,但在测试后它没有用 - 不幸的是,到那时取消我的投票为时已晚!代码无法编译(不能通过 FileAccess.Read 和类似于 CreateFile() 并且如果您键入 cast 枚举代码不会运行 - 不能通过 null 作为 hTemplate。 @Oliver:我已经 7 年没有看过这段代码了(looks at watch),所以事情可能已经改变了。我很确定它在 7 年前与 VS2005 中的 C#/.NET 2.0 一起工作(或者可能是 VS2008,不确定我当时是否已经切换。)我会看看我是否能找到我正在使用的原始代码回到那个时候,如果我找到它就发回来。【参考方案2】:

Fix 的响应几乎是正确的,并且比 PInvoke 更好。 但它有错误并且不起作用......

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

const FileOptions FileFlagNoBuffering = (FileOptions)0x20000000;

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

几条规则:

    blockSize 必须与硬盘簇大小对齐(大多数情况下为 4096) 文件位置更改必须与簇大小对齐 您不能读取/写入小于 blockSize 或块未与其大小对齐

并且不要忘记 - 还有 HDD 缓存(它比 OS 缓存更慢且更小),您无法关闭它(但有时 FileOptions.WriteThrough 有助于不缓存写入)。使用这些选项,您没有理由刷新,但请确保您已正确测试此方法不会减慢速度,以防您的缓存实现速度较慢。

【讨论】:

【参考方案3】:

为什么要DIY?

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

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

【讨论】:

【参考方案4】:
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);

【讨论】:

使用二进制 and 有效地杀死了所有选项,但另一方面它不太可能是拼写错误,因此我想知道使用它的原因是什么。【参考方案5】:

我找到了this 文章,这似乎是一个复杂的程序,因为您还必须刷新其他缓存。

【讨论】:

以上是关于如何在 C# 中清空/刷新 Windows READ 磁盘缓存?的主要内容,如果未能解决你的问题,请参考以下文章

asp.NET中,密码输入框一刷新后输入的密码就清空,但刷新后我想保留刷新前输入的密码怎么做!

如何在 Windows 资源管理器中刷新文件的缩略图?

如何清空C#中dataGridView的某一行数据??

Chrome浏览器如何强制刷新

关于c#中的datatable,不知道如何清空里面的数据

C#中如何动态获取剪贴板中的内容(我想实现如果其中有内容就清空,在C#中不要实现复制,粘贴功能)?