如何使用FILE_FLAG_NO_BUFFERING在c#invoke win32 CreateFile api中禁用磁盘缓存

时间:2012-01-01 10:05:26

标签: c# pinvoke filestream createfile

每个人,我有很多文件每秒写入磁盘,我想禁用磁盘缓存以提高性能,谷歌搜索找到解决方案:win32 CreateFile方法与FILE_FLAG_NO_BUFFERING和How to empty/flush Windows READ disk cache in C#?

我写了一些代码来测试是否可行:

const int FILE_FLAG_NO_BUFFERING = unchecked((int)0x20000000);

[DllImport("KERNEL32", SetLastError = true, CharSet = CharSet.Auto, BestFitMapping = false)]
static extern SafeFileHandle CreateFile(
      String fileName,
      int desiredAccess,
      System.IO.FileShare shareMode,
      IntPtr              securityAttrs,
      System.IO.FileMode  creationDisposition,
      int                 flagsAndAttributes,
      IntPtr              templateFile);

static void Main(string[] args)
{
    var handler = CreateFile(@"d:\temp.bin", (int)FileAccess.Write, FileShare.None,IntPtr.Zero, FileMode.Create, FILE_FLAG_NO_BUFFERING, IntPtr.Zero);
    var stream = new FileStream(handler, FileAccess.Write, BlockSize);//BlockSize=4096
    byte[] array = Encoding.UTF8.GetBytes("hello,world");
    stream.Write(array, 0, array.Length);
    stream.Close();
}

运行此程序时,应用程序会出现异常: IO操作无效。很可能文件将变得太长或未打开句柄以支持同步IO操作

之后,我发现了这篇文章When you create an object with constraints, you have to make sure everybody who uses the object understands those constraints,但我无法完全理解,所以我将代码更改为测试:

var stream = new FileStream(handler, FileAccess.Write, 4096);
byte[] ioBuffer = new byte[4096];
byte[] array = Encoding.UTF8.GetBytes("hello,world");
Array.Copy(array, ioBuffer, array.Length);
stream.Write(ioBuffer, 0, ioBuffer.Length);
stream.Close();

它运行正常,但我只想要“你好,世界”字节不是全部。我尝试将块大小更改为1或其他整数(不是512多个)得到相同的错误。我也尝试win32 WriteFile api也得到相同的error.someone可以帮帮我吗?

2 个答案:

答案 0 :(得分:4)

无缓冲模式下的CreateFile()函数强加strict requirements可能和不可能做的事情。具有特定大小的缓冲区(设备扇区大小的多个)是其中之一。

现在,只有在代码中使用缓冲时,才能以这种方式改进文件写入。如果你想在没有缓冲的情况下写入10个字节,那么No Buffering模式将无法帮助你。

答案 1 :(得分:1)

如果我理解你的要求,这就是我先试试的:

创建一个队列,其中包含内存中的数据和磁盘上的目标文件。 你首先将文件写入内存,然后在另一个线程上开始通过队列,打开基于io-completion port的文件流句柄(isAsync = True) - 只是不要打开太多的文件,因为你在某些时候'由于缓存垃圾等问题,可能会开始失去性能。您需要进行分析以查看系统和ssd的最佳数量。

每次打开后,您都可以使用异步文件流方法Begin ...开始将数据从内存写入文件。 isAsync提出了一些要求,因此这可能不像在正常情况下使用文件流那样容易在每个角落工作。

使用另一个线程创建文件是否会有任何改进,另一个线程是否使用async api写入它们,如果创建/打开文件可能会阻塞,则可能就是这种情况。 SSD在内部执行各种操作以快速访问数据,因此当您开始执行此类极端性能时,SSD控制器之间可能存在明显差异。如果控制器驱动程序没有很好地实现,OS / Windows也可能开始感觉迟缓或冻结。硬件基准测试站点并没有真正强调这种特殊情况(例如,尽快创建并将x KB写入百万个文件),毫无疑问,有些驱动程序比其他驱动程序慢。