Windows XP上的FSCTL_MOVE_FILE,系统卷,FAT32



我在对windows xp、fat32系统卷上的文件进行碎片整理时遇到问题。我不是在写碎片整理程序,而是解决方案的一部分,需要在磁盘上连续放置一组特定的文件。为了确保这一点,我使用FSCTL_MOVE_FILE ioctl将文件扩展区移动到卷上足够大小的单个可用空间扩展区中。过程如下:

1) 创建文件:

return m_file.Create(path,
GENERIC_READ | GENERIC_WRITE,
0, NULL,
CREATE_ALWAYS,
FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH |
FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
NULL);

2) 用零填充文件。

3) 检查文件是否碎片化,如果碎片化,请使用FSCTL_GET_volume_bitmap获取卷位图,找到足够大小的空闲簇链。

4) 使用FSCTL_MOVE_FILE将文件碎片整理到找到的范围中,例如:

MOVE_FILE_DATA input;
input.FileHandle = fileHandle;
input.StartingVcn.QuadPart = 0;
input.StartingLcn.QuadPart = freeExtent.lcn;
input.ClusterCount = totalFileClusters;
DWORD bytesReturned = 0; // unused
::DeviceIoControl(
volumeHandle,
FSCTL_MOVE_FILE,
&input,
sizeof(input),
NULL,
0,
&bytesReturned,
NULL);

最后一个调用在NTFS系统和常规卷上运行良好。XP上的非系统卷也没有问题。然而,在XP上的FAT32系统卷上,我几乎总是会出现INVALID_ARGUMENT(87)错误。文件相当大,大约700MB。该卷具有大约10GB的可用空间。在fsctl失败后,可以看到在错误发生之前,文件的一部分实际上已经被移动了。我试了好几次,但到目前为止,50次都失败了。我知道,以这种方式移动一个大文件可能会失败,因为以前空闲的集群会被卷上的其他东西占用,尤其是当卷有很多活动(就像系统卷通常有)时。但我不知道如何减轻这种情况,因为我没有内核存在。我做错了什么和/或我该如何做得更好?

这里的简短答案是否定的,您无法从用户模式中实现。您将始终与操作文件系统的其他应用程序/操作系统进程竞争。

如果你真的想走这条路,你需要编写一个相当复杂的内核驱动程序(文件系统迷你过滤器)来帮助同步这个操作。这可能会变得棘手,尤其是对于承载页面/交换文件的卷上的移动。

祝你好运!

两个问题。首先,在一个实时系统中,你总是在与其他活动竞争(正如前一位回答者所建议的那样)。例如,一旦检索到卷位图,它可能已经过期,原因是您看不到其他进程中的操作。

其次,FAT32可能对你一次移动的次数有限制。也许您应该考虑以256Kb的块(也称为缓存管理器映射视图大小)移动文件。如果你遇到了一个错误,比如击中了以前免费的空间,你就没有那么多的工作要做了。

最后,如果你有一个700Mb的文件,如果它存在于7001Mb的块中,我怀疑你是否会看到比单个700Mb块有任何显著的性能改进。

最新更新