我注意到写入文件,关闭它并将其移动到目的地随机地在Vista上失败.具体来说,MoveFileEx()将返回ERROR_ACCESS_DENIED
没有明显的原因.这至少发生在Vista SP1上(32位).在XP SP3上不会发生.
在互联网上找到关于完全相同问题的这个线程,没有真正的解决方案.到目前为止看起来错误是由Vista的搜索索引器引起的,见下文.
给出的代码示例足以重现问题.我也在这里粘贴它:
#include#include #include 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上不会发生这种情况.根本没有防病毒运行; 并没有其他奇怪的后台进程(机器几乎是vanilla OS安装+ Visual Studio).
编辑:通过Process Monitor进一步挖掘(感谢@sixlettervariables),我看不出任何特别糟糕的东西.每次测试迭代都会产生176个磁盘操作,其中大部分来自SearchProtocolHost.exe(搜索索引器).如果搜索索引服务停止,则不会发生错误,因此它看起来像是罪魁祸首.
在失败时(当应用程序获取时ERROR_ACCESS_DENIED
),SearchProtocolHost.exe有两个CreateFile(s)到detination文件(bbb)打开与读/写/删除共享模式,所以它应该没问题.其中一个开放之后是机会锁(FSCTL_REQUEST_FILTER_OPLOCK
),也许这是原因?
无论如何,我发现我可以通过在文件上设置FILE_ATTRIBUTE_TEMPORARY
和FILE_ATTRIBUTE_NOT_CONTENT_INDEXED
标记来避免这个问题.看起来它FILE_ATTRIBUTE_NOT_CONTENT_INDEXED
本身就足够了,但将文件标记为临时文件也会大大减少搜索索引器导致的磁盘操作.
但这不是一个真正的解决方案.我的意思是,如果一个应用程序不能指望能够创建一个文件并重命名它,因为一些Vista的搜索索引器正在搞乱它,那就完全疯了!它应该继续重试吗?对用户大喊大叫(非常不受欢迎)?做点别的吗?