C# 如何在c中禁用磁盘缓存调用win32 CreateFile api并使用文件\u标志\u无\u缓冲

C# 如何在c中禁用磁盘缓存调用win32 CreateFile api并使用文件\u标志\u无\u缓冲,c#,pinvoke,filestream,createfile,C#,Pinvoke,Filestream,Createfile,各位,我有很多文件每秒写入磁盘,我想禁用磁盘缓存以提高性能,我在谷歌搜索中找到了一个解决方案:win32 CreateFile方法,带有文件标志和无缓冲 我编写了一些代码来测试是否可以工作: const int FILE_FLAG_NO_BUFFERING = unchecked((int)0x20000000); [DllImport("KERNEL32", SetLastError = true, CharSet = CharSet.Auto, BestFitMapping = false

各位,我有很多文件每秒写入磁盘,我想禁用磁盘缓存以提高性能,我在谷歌搜索中找到了一个解决方案:win32 CreateFile方法,带有文件标志和无缓冲

我编写了一些代码来测试是否可以工作:

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操作

后来,我找到了这篇文章,但我不能完全理解,所以我将代码改为测试:

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

它运行正常,但我只想要hello,world bytes不是全部。我正在尝试将blocksize更改为1或其他整数,而不是512倍数,以获得相同的错误。我还尝试win32 WriteFile api也获得相同的错误。有人可以帮我吗?

无缓冲模式下的CreateFile函数会强制执行可能执行的操作和可能不执行的操作。有一个特定大小的设备扇区大小倍数的缓冲区就是其中之一


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

如果我正确理解了您的需求,我会首先尝试以下内容:

创建一个队列,队列中包含内存中的数据和磁盘上的目标文件。 首先将文件写入内存,然后在另一个线程上开始遍历队列,打开基于io完成端口的filestream句柄isAsync=True-只是不要打开太多,因为在某个时候,您可能会由于缓存破坏等原因开始丢失性能。您需要配置文件,以查看系统和ssd的最佳数量

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


使用另一个线程创建文件和使用异步api写入文件是否会有任何改进,只有在创建/打开文件可能会被阻止的情况下才会出现这种情况。SSD在内部执行各种操作以保持对数据的快速访问,因此,当您开始执行这种极端性能的操作时,SSD控制器之间可能存在明显的差异。如果控制器驱动程序没有很好地实现,操作系统/窗口也可能会开始感觉迟钝或冻结。硬件基准网站并没有真正强调这种特殊情况,例如尽快创建x KB并将其写入百万个文件,毫无疑问,有些驱动程序比其他驱动程序慢。

是的,谢谢。如果我每秒有很多文件,每秒有25个文件,文件的平均大小是60-80k,我可以使用无缓冲区吗?@user902408在您的特定场景中,无缓冲模式没有帮助。例如,在生成大量XML文件时,这种模式很好,其中大量的标记和其他数据都是以小块的形式写入的。但是对于60-80 kb的大文件,您不会获得太多。@user902408根据您对文件的进一步操作,文件中的虚拟文件系统FS可能会工作得更好,因为它提供了缓冲级别,并且可以处理磁盘上的一个大文件,可能没有您想要的缓冲。您不必pinvoke,它以FileOptions.WriteThrough的形式提供。由于必须等待磁盘,因此这种方式的写入速度要慢得多。最好使用默认选项,即不要使用直写,而是一次性写入整个60-80kb的文件。