等待文件可供 Win32 读取

发布于 2024-08-11 14:26:07 字数 677 浏览 4 评论 0原文

我正在通过同步调用 ReadDirectoryChangesW 来查看目录。当新文件可用时,我尝试使用 CreateFile 以及 GENERIC_READFILE_SHARE_READ 立即访问它,但这给了我 ERROR_SHARING_VIOLATION< /代码>。当我尝试读取文件时,将文件放入监视目录的进程尚未完成写入。

有什么方法可以可靠地等待文件可供读取吗?我可以将该方法放入如下循环中,但我希望有更好的方法。

while ((hFile = CreateFile (path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
{
    if (GetLastError() == ERROR_SHARING_VIOLATION)
        Sleep (500);
    else
        break; // some other error occurred
}

if (hFile == INVALID_HANDLE_VALUE)
{
    // deal with other error
    return 0;
}

ReadFile (...);

I'm watching a directory by calling ReadDirectoryChangesW synchronously. When a new file is available, I try to access it immediately with CreateFile with GENERIC_READ and FILE_SHARE_READ, but this gives me ERROR_SHARING_VIOLATION. The process that put the file in the watched directory does not finish writing by the time I try to read it.

Is there any way to reliably wait until the file is available for reading? I can put the method into a loop like the one below, but I'm hoping there's a better way.

while ((hFile = CreateFile (path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
{
    if (GetLastError() == ERROR_SHARING_VIOLATION)
        Sleep (500);
    else
        break; // some other error occurred
}

if (hFile == INVALID_HANDLE_VALUE)
{
    // deal with other error
    return 0;
}

ReadFile (...);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

浊酒尽余欢 2024-08-18 14:26:07

我认为没有针对您正在寻找的活动类型的通知,但作为一种改进,我建议逐步延迟。这样,您将获得对拖/放等操作的快速响应时间,并且如果用户在 Excel 中将文件打开一个小时,也不会因紧密循环而占用 CPU。

int delay= 10;
while ((hFile = CreateFile (path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
{
    if (GetLastError() == ERROR_SHARING_VIOLATION) {
        Sleep (delay);
        if (delay<5120) // max delay approx 5.Sec
            delay*= 2;
    }
    else
        break; // some other error occurred
}

I don't think there is a notification for the kind of event you're looking for, but as an improvement, I'd suggest progressive delays. This way you will get fast response times for stuff like a drag/drop and won't hog the CPU with a tight loop if the user keeps the file open for an hour in Excel.

int delay= 10;
while ((hFile = CreateFile (path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
{
    if (GetLastError() == ERROR_SHARING_VIOLATION) {
        Sleep (delay);
        if (delay<5120) // max delay approx 5.Sec
            delay*= 2;
    }
    else
        break; // some other error occurred
}
ぃ双果 2024-08-18 14:26:07

据我所知,没有用于通知已关闭文件的用户模式 ​​API。您提出的循环可能确实是最好的方法。您唯一可以做的另一件事就是在过滤器驱动程序和进程监视器中监视 CloseFile ,但是糟糕......

There's no user-mode API for notifications on a closed file that I'm aware of. The loop you've proposed is really probably the best way. The only other thing you could do would be to watch for CloseFile in a filter driver ala Process Monitor, but yuck...

葵雨 2024-08-18 14:26:07

正如 @Matt Davis 所说,不幸的是没有用户模式 ​​API,但有一个解决方法,根据您的用例(我在下面写了我的)可能会做您想要的事情。

过去对我有用的是在调用 ReadDirectoryChangesW 时注册 FILE_NOTIFY_CHANGE_LAST_WRITE 而不是 FILE_NOTIFY_CHANGE_FILE_NAME

ZeroMemory(&overlapped, sizeof(OVERLAPPED));
overlapped.hEvent = hChangeEvent;

// ...    
ReadDirectoryChangesW(hSpoolPath,
                      eventBuffer,
                      EVENT_BUF_LENGTH,
                      FALSE,
                      FILE_NOTIFY_CHANGE_LAST_WRITE, // <----
                      NULL,
                      &overlapped,
                      NULL);
// ...
HANDLE events[2];

events[0] = hChangeEvent;
events[1] = hCancelEvent;

DWORD wRc = WaitForMultipleObjects(2, events, FALSE, DIRECTORY_WATCH_TIMEOUT);

最后一次写入时间创建文件并写入文件后,一旦拥有进程关闭句柄,该文件就会被更新。

我的用例是一个进程通过 TCP/IP 接收 HTTP 请求并将 HTTP 主体写入一个目录,另一个进程在接收进程完成写入(并因此关闭句柄)后立即拾取它。 http-server 是唯一写入该目录的进程,因此我可以依赖创建-写入-关闭模式。

As @Matt Davis said, there is unfortunately no user-mode API but there is a workaround that depending on your use-case (I've written mine below) may do just what you want.

What worked for me in the past was registering for FILE_NOTIFY_CHANGE_LAST_WRITE instead of FILE_NOTIFY_CHANGE_FILE_NAME when calling ReadDirectoryChangesW:

ZeroMemory(&overlapped, sizeof(OVERLAPPED));
overlapped.hEvent = hChangeEvent;

// ...    
ReadDirectoryChangesW(hSpoolPath,
                      eventBuffer,
                      EVENT_BUF_LENGTH,
                      FALSE,
                      FILE_NOTIFY_CHANGE_LAST_WRITE, // <----
                      NULL,
                      &overlapped,
                      NULL);
// ...
HANDLE events[2];

events[0] = hChangeEvent;
events[1] = hCancelEvent;

DWORD wRc = WaitForMultipleObjects(2, events, FALSE, DIRECTORY_WATCH_TIMEOUT);

The last write time gets updated as soon as the owning process closes the handle after creating the file and writing to it.

My use-case was one process that received HTTP-requests via TCP/IP and wrote the HTTP-body into a directory, where another process picked it up as soon as the receiving process was finished writing (and consequently closing the handle) it. The http-server was the only process that wrote to that directory, so I could rely on the create-write-close pattern.

唯憾梦倾城 2024-08-18 14:26:07

如果您了解文件的创建方式,可以等到文件停止增长 X 秒,或者等到哨兵文件被删除。或者感知创建它们的程序的状态。

If you know something about how the file is created, maybe wait until the file stops growing for X seconds, or wait until a sentinel file is deleted. Or sense the state of the program which creates them.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文