我在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次都失败了。我知道以这种方式移动大文件可能会失败,因为之前的免费群集会在卷上被其他东西占用,特别是如果卷有很多活动(比如系统卷通常有)。但我不知道如何缓解这一点,因为我没有内核存在。我做错了什么和/或我怎么能做得更好?
答案 0 :(得分:0)
这里简短的答案是否定的,你无法从用户模式到达那里。您将始终与正在操作文件系统的其他应用程序/操作系统进程竞争。
如果您真的想沿着这条路走下去,那么您将需要编写一个相当复杂的内核驱动程序(File System Minifilter)来协助同步此操作。这可能会变得棘手,特别是对于托管页面/交换文件的卷上的移动。
祝你好运!答案 1 :(得分:0)
两个问题。首先,在现场系统上,你总是在与其他活动竞争(正如之前的回答者建议的那样)。例如,一旦检索到卷位图,由于您没有看到其他进程中的操作,它可能已经过时了。
其次,FAT32可能会限制您一次可以移动多少。也许您应该考虑以256Kb(也就是缓存管理器映射视图大小)的块来移动文件。 如果您遇到错误,例如点击空间以前是免费的,那么您的工作要少得多。
最后,如果你有一个700Mb的文件,如果它存在于700个1Mb的块中,我怀疑你会发现在一个700Mb的块上有任何显着的性能提升。