有没有办法在 Windows 中使用 C# 以编程方式禁用磁盘驱动器上的写入缓存策略?

Posted

技术标签:

【中文标题】有没有办法在 Windows 中使用 C# 以编程方式禁用磁盘驱动器上的写入缓存策略?【英文标题】:Is there a way to disable the write behind caching policy on a disk drive programmatically using C# in windows? 【发布时间】:2020-03-04 20:08:30 【问题描述】:

我需要删除我们服务器磁盘驱动器上缓存的写入。在 Windows 中这样做 ==> 设备管理器 ==> 磁盘驱动器 ==>(右键单击)属性 ==> 策略 ==>(复选框)启用缓存后写入 |很简单,但 Windows 会自动重新启用它。我相信这会发生在更新中。

我想知道我是否可以使用 C# 访问这些策略以每天禁用它们。

有人知道方法吗?

我查看了 DriveInfo,但没有找到访问策略的方法。

【问题讨论】:

在 C:blogs.msdn.microsoft.com/winsdk/2009/10/09/… gpo?肯定是最简单的 @OlivierRogier,我也找到了该链接。我将使用注册表项与系统重新启动相结合来关闭缓存后写入。如果它像我期望的那样工作,将保持更新这篇文章。这种行为确实会损害数据库的完整性。 【参考方案1】:

我有 2 个可能的解决方案,它们都旨在解决每个文件级别的问题,而不是操作系统设置级别。

如果您想为了策略而更改策略,那么 Windows 策略管理可能会为此提供一个选项。

WriteThrough

现在这里有一大堆缓存在起作用——应用程序/类、操作系统、磁盘电子中的 RAM。而且我不确定它是否会影响您担心的特定缓存。但 FileStream 有一个名为“WriteThrough”的选项:

表示系统应该通过任何中间缓存写入并直接进入磁盘。

https://docs.microsoft.com/en-us/dotnet/api/system.io.fileoptions

应用程序/类缓存是微不足道的,并且 99% 被禁用。

“系统”的提及向我表明它将进入操作系统缓存(您似乎很担心)。但这只是文档中的一行,所以我不能肯定地说它会下降到操作系统级别。但是,如果我要定义一个选项用于记录到文件并假设在所有现有记录器上启用,就是这样。

假设这不是用于日志记录或类似的流式工作,核心问题是部分写入损坏文件的危险,一个小的重新设计可以解决这个问题。

写入临时文件 -> 移动

避免在(重新)写入文件时损坏文件的一种可靠方法是写入不同的临时文件 - 然后只需移动这些文件即可(理想情况下只会更改文件系统名称条目)。不久前,在文字处理器中看到这种行为后,我确实为此编写了一些示例代码:

string sourcepath; //containts the source file path, set by other code
string temppath; //containts the path of the tempfile. Should be in the same folder, and thus same partiion

//Open both Streams, can use a single using for this
//The supression of any Buffering on the output should be optional and will be detrimental to performance
using(var sourceStream = File.OpenRead(sourcepath), 
  outStream = File.Create(temppath, 0, FileOptions.WriteThrough ))

    string line = "";

    //itterte over the input
    while((line = streamReader.ReadLine()) != null)
        //do processing on line here

        outStream.Write(line);
    


//replace the files. Pretty sure it will just overwrite without asking
File.Move(temppath, sourcepath);

当然,缺点是您将暂时需要两倍的磁盘空间,并且在某些修改上会导致大量额外的写入工作。

【讨论】:

感谢克里斯托弗的快速回复,我应该更好地解释一下自己。受缓存后写入影响的程序不是我自己的,也不是我可以编辑的。它的医疗软件及其数据完整性受到 Windows 开启缓存后写入功能的影响。例如,两个用户可能同时使用相同的功能。如果没有在缓存后面写入,则其中一个用户将被拒绝。不幸的是,现在似乎数据库查询被缓存并在以后提交,您可以认为这是灾难性的。 @Blixem 你检查过 Windows 策略吗?如果有一件事可以设置值并在更新中保持设置,那就是它。 |我会亲自运行没有缓存的程序。最好安全地失败,然后在看不见的危险中成功。事实上,如果两个人使用相同的功能,写入缓存实际上存在更新竞争条件的危险。 @Blixem:处理此类事情的 WPF 方式是:“如果您无法更改它,请将访问权限包装在您可以更改的内容中。”由于他们需要具有 ChangeNotification 的属性,因此经常会遇到“无法更改它”的情况。听起来确实很像 Programm 是某种服务器。也许你可以抽象出你自己制作的 WebService 背后的旧代码,然后可以做一些很好的事情,比如“等待 15 秒来获得锁,然后再拒绝函数调用”。【参考方案2】:

好的,所以我找到了解决此问题的方法。

正如 OlivierRogier 也提到的。此设置似乎存储在以下注册表中:

HKLM\SYSTEM\CurrentControlSet\Enum\(IDE 或 SCSI)\Diskxxxxxxxxxxxx\DeviceParameters\Disk 键:UserWriteCacheSetting 其中 xxxxxxx 是制造商信息。

链接HERE

我设置了一些每天检查此设置的代码 => 更改它 => 重新启动计算机。如果需要,将共享代码。

感谢大家的意见。 Blixem

【讨论】:

以上是关于有没有办法在 Windows 中使用 C# 以编程方式禁用磁盘驱动器上的写入缓存策略?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# 中更改 Windows 中的扬声器配置?

有没有办法在 Windows 上的 C++ 中以编程方式设置环境路径?

以编程方式生成 SSH 密钥对(c# windows)

有没有办法在多 GPU 环境中以编程方式选择渲染 GPU? (视窗)

有没有办法在 Windows 10 中使用蓝牙 LE 库 C# 与传感器或微控制器通信?

在 C# 中以编程方式从 Excel 文件中大量导入数据到 Access