7

我注意到在 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 上不会发生。根本没有运行防病毒软件;并且没有其他奇怪的后台进程(机器几乎是 vanilla OS install + Visual Studio)。

编辑:通过进程监视器进一步挖掘(感谢@sixlettervariables),我看不到任何特别糟糕的事情。每次测试迭代都会产生 176 次磁盘操作,其中大部分来自 SearchProtocolHost.exe(搜索索引器)。如果停止搜索索引服务,则不会发生错误,因此看起来它是罪魁祸首。

在失败时(当应用程序获取时ERROR_ACCESS_DENIED),SearchProtocolHost.exe 有两个 CreateFile(s) 到以读/写/删除共享模式打开的目标文件 (bbb),所以应该没问题。其中一个打开之后是机会锁定(FSCTL_REQUEST_FILTER_OPLOCK),也许这就是原因?

无论如何,我发现我可以通过在文件上设置FILE_ATTRIBUTE_TEMPORARYFILE_ATTRIBUTE_NOT_CONTENT_INDEXED标志来避免这个问题。它本身看起来FILE_ATTRIBUTE_NOT_CONTENT_INDEXED就足够了,但是将文件标记为临时文件也大大减少了由搜索索引器引起的磁盘操作。

但这并不是真正的解决方案。我的意思是,如果一个应用程序不能指望能够创建一个文件并重命名它,因为某些 Vista 的搜索索引器正在搞乱它,那真是太疯狂了!它应该继续重试吗?对用户大喊大叫(这是非常不可取的)?做点别的吗?

4

4 回答 4

4

我建议您使用Process Monitor (编辑:艺术家以前称为 FileMon)来观察并查看究竟是哪个应用程序妨碍了您。它可以向您显示在您的机器上进行的文件系统调用的整个跟踪。

(编辑:感谢@moocha 更改应用程序)

于 2008-09-30T15:21:01.573 回答
1

我会说是您的防病毒软件或 Windows 索引同时弄乱了文件。您可以在没有防病毒软件的情况下运行相同的测试吗?然后再次运行它,确保临时文件是在没有被 Windows Search 索引的地方创建的?

于 2008-09-30T15:13:16.960 回答
0

这通常意味着其他东西对相关文件有一个打开的句柄,也许是一个正在运行的活动病毒扫描程序?您是否尝试过从 Sysinternals站点运行诸如 Process Monitor 之类的东西?您应该过滤所有文件操作并更好地了解引擎盖下发生的事情。

于 2008-09-30T15:18:09.473 回答
0

Windows 有一个用于存储应用程序文件的特殊位置,我认为它没有索引(至少默认情况下没有)。在 Vista 中,路径是:

C:\Users\user name\AppData

I suggest you put your files there if it is appropriate for your application.

于 2008-10-01T20:56:48.467 回答