为什么fsutil.exe花费较少的时间将大文件写入磁盘而不是以编程方式?

时间:2009-12-12 12:01:37

标签: windows file-io fsutil

这个问题是根据这个主题: creating a huge dummy file in a matter of seconds in c#

我刚检查了xp / vista / 7中的fsutil.exe,将大量虚拟数据写入存储磁盘,与程序化方式相比,编写这么大的文件所需的时间更短。

当我尝试在.net的帮助下做同样的事情时,它将比fsutil.exe花费更多的时间。

注意:我知道.net不使用本机代码,因为我刚刚使用native api检查了这个问题,如下所示:

long int size = DiskFree('L' - 64);
const char* full = "fulldisk.dsk";
__try{
Application->ProcessMessages();
HANDLE hf = CreateFile(full,
                       GENERIC_WRITE,
                       0,
                       0,
                       CREATE_ALWAYS,
                       0,
                       0);
SetFilePointer(hf, size, 0, FILE_BEGIN);
SetEndOfFile(hf);
CloseHandle(hf);
}__finally{
    ShowMessage("Finished");
    exit(0);

并且答案与.net结果相同。

但是在fsutil.exe的帮助下,它只需要比上面更短的持续时间或.net方法说它快2倍

示例: 用.net写400mb需要大约40秒 与fsutil.exe相同的数量大约需要20秒或更少。

有没有解释? 或哪个函数fsutil.exe确实使用具有这种显着速度的函数来编写?

4 个答案:

答案 0 :(得分:5)

我不知道fsutil到底在做什么,但我知道有两种方法来编写一个比你上面所做的更快的大文件(或者寻找你想要的长度并写入零,有相同的结果)。

这些方法的问题在于它们在您执行写入时将文件归零。

您可以通过以下任一方式避免零填充:

  1. 创建稀疏文件。大小标记在您想要的位置,但在您编写之前,数据实际上并不存在于磁盘上。所有未写区域的读取都将返回零。
  2. 使用SetFileValidData函数设置有效数据长度,而不先将文件归零。但是,由于潜在的安全问题,此命令需要提升权限。

答案 1 :(得分:2)

我同意最后的评论。我正在尝试使用minifilter驱动程序并在回调中捕获IRP_MJ_WRITE IRP。当我从cmd行或win32应用程序创建或写入文件时,我可以看到写入下来。但是当我使用“fsutil file createnew ...”命令创建文件时,我没有看到任何写入。我在NTFS卷上的win2k8 r2上看到了这种行为。我不认为(不确定100%)它也是一个稀疏文件。它可能在MFT中设置大小属性而不分配任何群集。 fsutil会检查可用空间,因此如果文件大小大于磁盘上的可用空间,则会出现错误1.

我还运行程序将FSCTL_GET_RETRIEVAL_POINTERS发送到该文件,我得到一个范围用于整个文件大小。但我相信它正在获取所有数据

答案 2 :(得分:1)

这可能是

  • 以汇编程序编写(原始致盲速度)
  • 用于执行此操作的本机C / C ++代码
  • 可能是一个未记录的系统调用来执行此操作或某些未在任何地方记录的技巧。

以上三点可能有一个非常重要的因素 - 当你考虑它时,当加载.NET代码时,它会被运行时监视(好吧,如果你有一个时间因素就不会引起注意炽热的快速机器 - 在低端的奔腾,这将是显而易见的,缓慢的负载)。

很可能它可能是用C / C ++编写的。如果它是用汇编程序编写的,它可能会让你感到惊讶。

您可以自己检查一下 - 查看可执行文件的文件大小,并将其与.NET的可执行文件进行比较。你可能会争辩说文件是压缩的,我怀疑它会是什么,因此倾向于排除这一点,微软不会那么远,我认为压缩可执行文件业务。

希望这能回答你的问题, 最好的祝福, 汤姆。

答案 3 :(得分:1)

fsutil仅在NTFS和exFAT上快速,而不是在FAT32,FAT16上 这是因为某些文件系统具有“初始化大小”概念,因此支持快速文件初始化。这只是保留集群但不会将它们清零,因为它在文件系统中注意到没有数据写入文件,有效读取将返回00填充的缓冲区。