2

我在对 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 次都失败了。我知道以这种方式移动大文件可能会失败,因为之前空闲的集群被卷上的其他东西占用,特别是如果卷有很多活动(就像系统卷通常有)。但是我不知道如何减轻这种情况,因为我没有内核存在。我做错了什么和/或我怎样才能做得更好?

4

2 回答 2

0

这里的简短回答是否定的,你不能从用户模式到达那里。您将始终与操作文件系统的其他应用程序/操作系统进程竞争。

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

祝你好运!

于 2012-12-12T05:12:07.957 回答
0

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

其次,FAT32 可能对您一次可以移动的数量有限制。也许您应该考虑以 256Kb 的块(又名缓存管理器映射视图大小)移动文件。如果您遇到错误,例如点击了以前空闲的空间,那么您需要推理的工作就会少得多。

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

于 2012-12-13T06:31:22.077 回答