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