Vista上的随机MoveFileEx失败
我注意到在Vista上写入文件,关闭文件并将其随机移动到目标位置的操作失败。具体来说,MoveFileEx()会在没有明显原因的情况下返回" ERROR_ACCESS_DENIED"。至少在Vista SP1(32位)上会发生这种情况。在XP SP3上不会发生。
在互联网上发现了与这个问题完全相同的线索,没有真正的解决方案。到目前为止,该错误似乎是由Vista的搜索索引器引起的,请参见下文。
此处给出的代码示例足以重现该问题。我也在这里粘贴:
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
bool test() {
unsigned char buf[] = {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99,
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99
};
HANDLE h;
DWORD nbytes;
LPCTSTR fn_tmp = "aaa";
LPCTSTR fn = "bbb";
h = CreateFile(fn_tmp, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_ALWAYS, 0, 0);
if (h == INVALID_HANDLE_VALUE) return 0;
if (!WriteFile(h, buf, sizeof buf, &nbytes, 0)) goto error;
if (!FlushFileBuffers(h)) goto error;
if (!CloseHandle(h)) goto error;
if (!MoveFileEx(fn_tmp, fn, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH)) {
printf("error=%d\n", GetLastError());
return 0;
}
return 1;
error:
CloseHandle(h);
return 0;
}
int main(int argc, char** argv) {
unsigned int i;
for (i = 0;; ++i) {
printf("*%u\n", i);
if (!test()) return 1;
}
return 0;
}
使用Visual Studio将其构建为控制台应用程序。正确的行为是打印测试编号的无限循环。在Vista SP1上,程序在随机迭代之后(通常在进行100次迭代之前)退出。
在Windows XP SP2上不会发生这种情况。根本没有运行防病毒软件;并且没有其他奇怪的后台进程(机器几乎是普通的OS安装+ Visual Studio)。
编辑:通过进程监视器进一步挖掘(感谢@sixlettervariables),我看不到任何特别糟糕的东西。每次测试迭代都会产生176个磁盘操作,其中大多数来自SearchProtocolHost.exe(搜索索引器)。如果搜索索引服务已停止,则不会发生任何错误,因此看起来是罪魁祸首。
在故障发生时(当应用程序获取到" ERROR_ACCESS_DENIED"时),SearchProtocolHost.exe会向目标文件(bbb)提供两个CreateFile,并以读取/写入/删除共享模式打开,因此应该可以。一个打开之后是机会锁定(FSCTL_REQUEST_FILTER_OPLOCK),也许是原因所在?
无论如何,我发现可以通过在文件上设置FILE_ATTRIBUTE_TEMPORARY和FILE_ATTRIBUTE_NOT_CONTENT_INDEXED标志来避免该问题。看起来`FILE_ATTRIBUTE_NOT_CONTENT_INDEXED'本身就足够了,但是将文件标记为临时也大大减少了由搜索索引器引起的磁盘操作。
但这不是一个真正的解决方案。我的意思是,如果某个应用程序不能期望能够创建文件并重命名该文件,因为某些Vista的搜索索引器将其弄乱了,那就太疯狂了!它应该继续重试吗?对用户大喊(这是非常不希望的)?还有其他事吗
解决方案
我想说的是防病毒软件或者Windows Indexing同时破坏了文件。我们可以在没有防病毒软件的情况下运行相同的测试吗?然后再次运行它,以确保在Windows搜索未索引的位置创建了临时文件?
这通常意味着其他文件在该文件上有打开的句柄,也许正在运行一个活动的病毒扫描程序?我们是否尝试过从Sysinternals网站运行类似Process Monitor之类的东西?我们应该过滤所有文件操作,以更好地了解引擎盖下的情况。
我建议我们使用Process Monitor(编辑:原为FileMon的艺术家)观察并查看到底哪个应用程序在妨碍工作。它可以显示我们在计算机上进行的文件系统调用的整个轨迹。
(编辑:感谢@moocha的应用程序更改)
Windows有一个用于存储应用程序文件的特殊位置,我认为它没有索引(至少默认情况下不是)。在Vista中,路径为:
C:\ Users \用户名\ AppData
我建议我们将文件放在适合应用程序的位置。

