【问题标题】:Flush disk write cache刷新磁盘写缓存
【发布时间】:2010-09-15 11:19:24
【问题描述】:

当 Windows XP 和 Vista 中的磁盘策略设置为在硬盘上启用写入缓存时,有没有办法刷新刚刚写入的文件,并确保它已提交到磁盘?

我想在 C++ 中以编程方式执行此操作。

关闭文件确实会在应用程序级别执行刷新,但不会在操作系统级别执行。如果在关闭文件后,但在操作系统刷新磁盘写入缓存之前断开 PC 的电源,则即使文件已关闭,文件也会丢失。

【问题讨论】:

  • 你的意思是编程吗?这个问题没有说清楚
  • 我们假设您的问题是关于编程的,但您没有指定开发环境。

标签: windows windows-xp disk


【解决方案1】:

.NET FileStream.Flush() 不会刷新该文件内容的 Windows 缓存; Flush() 仅刷新 .NET 内部文件缓冲区。在 .NET 4.0 中,Microsoft 通过向 Flush() 添加一个可选参数来解决此问题,如果设置为 true,则会调用 FlushFileSystemBuffers。在 .NET 3.5 及以下版本中,您唯一的选择是通过 pinvoke 调用 FlushFileBuffers。请参阅 MSDN 的FileStream.Flush 社区评论了解如何执行此操作。

【讨论】:

  • 警告:.Net 4.0 Flush(true) 不能修复它!!!! MS 错误报告here 说 file.Flush(true) 已损坏,然后修复,但没有说明它是在哪个版本或服务包中修复的!听起来错误是如果内部 .NET FileStream 缓冲区为空,则 Flush(true) 什么也没做??
【解决方案2】:

您不应该在关闭文件时修复此问题。 Windows 将缓存,除非您打开将FILE_FLAG_WRITE_THROUGH 传递给 CreateFile() 的文件。

您可能还想传递FILE_FLAG_NO_BUFFERING;这告诉 Windows 不要在缓存中保留字节的副本。

根据 MSDN 上的 CreateFile 文档,这比 FlushFileBuffers() 更有效。

另请参阅 MSDN 上的 file bufferingfile caching

【讨论】:

    【解决方案3】:

    你还没有指定开发环境,所以:

    .Net

    IO 流有一个 .Flush 方法,可以满足您的需求。

    Win32 API

    FlushFileBuffers 调用,它将文件句柄作为参数。

    编辑(基于 OA 的评论):FlushFileBuffers 不需要管理权限;只有当传递给它的句柄是卷的句柄,而不是单个文件的句柄时,它才会这样做。

    【讨论】:

    • 这似乎可行。不幸的是,应用程序必须能够在没有管理权限的情况下运行。
    • 我找不到这个 .NET 方法。据我所知,框架使用 FlushFileBuffers 的唯一地方是 SerialStream。我怀疑 p/invoking FlushFileBuffers 是安全的选择。
    • 我发现通过 pInvoke 调用 FlushFileBuffers 会导致异常(stackoverflow.com/q/9195807/4540)。在 .NET 4 下,按照@jimvfr 的建议 (stackoverflow.com/a/3992428/4540) 调用 FileStream.Flush(true) 会更容易、更安全。
    【解决方案4】:

    您还应该注意,您的数据可能不会被刷新到实际磁盘,即使在调用框架 API 的刷新方法时也是如此。

    调用 flush 方法只会告诉内核将其页面刷新到磁盘。但是,如果您打开了磁盘写入缓存,则可以无限期地延迟实际的写入过程。

    为了确保您的数据被写入物理层,您必须关闭操作系统中的写入缓存。在处理大量小型 io 操作时,这通常会导致性能损失高达一到两个数量级。 基于电池的支持 (UPS) 或接受命令以刷新磁盘写入缓存的磁盘是解决此问题的另一种选择。

    【讨论】:

    • Windows 将强制刷新重要数据的磁盘缓存,除非磁盘策略已设置为“关闭 Windows 写入缓存缓冲区刷新”
    • 当然会。但是,如果打开硬盘的写入缓存,则磁盘可能会停止写入操作。阅读,例如:support.microsoft.com/kb/259716/EN-US 引用:“通过启用写入缓存,如果机器遇到电源、设备或系统故障并且无法正常关闭,则可能会发生文件系统损坏和/或数据丢失。”
    • 实际上,无论是否打开了写入缓存缓冲,即使打开了写入缓存刷新(以前称为“高级性能复选框”),Windows 都会在 FlushFileBuffers() 上强制刷新缓存。
    【解决方案5】:

    从微软文档中,您将使用_flushall 并在 COMMODE.OBJ 中进行链接,以确保所有缓冲区都已提交到磁盘。

    【讨论】:

    • 我们还必须在 fopen() 期间添加“c”模式选项
    【解决方案6】:

    请看这里:https://jeffpar.github.io/kbarchive/kb/066/Q66052/

    当您最初使用 fopen 打开文件时,将“c”模式选项作为最后一个选项:

    fopen( path, "wc") // w - write mode, c - allow immediate commit to disk
    

    然后当你想强制刷新到磁盘时,调用

    _flushall()
    

    我们在打电话之前打了这个电话

    fclose()
    

    我们遇到了您描述的确切问题,这种方法解决了它。

    请注意,这种方法不需要像其他人提到的那样,FlushFileBuffers 确实需要管理权限。

    来自上述网站:

    “Microsoft C/C++ 7.0 版为 fopen() 引入了“c”模式选项 功能。当应用程序打开文件并指定“c”模式时, 运行时库将文件缓冲区的内容写入磁盘,当 应用程序调用 fflush() 或 _flushall() 函数。 "

    【讨论】:

      猜你喜欢
      • 2010-09-10
      • 2011-01-28
      • 2015-07-03
      • 1970-01-01
      • 2011-04-04
      • 2016-08-23
      • 2010-09-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多