- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我调用 ReadDirectoryChangesW
异步监视后台线程中的目录更改。
这是如何打开目录 ( basePath
) 并启动“读取”线程的:
m_hDIR = CreateFileW(
basePath,
FILE_LIST_DIRECTORY | GENERIC_READ,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
NULL);
if (m_hDIR == INVALID_HANDLE_VALUE)
throw CrException(CrWin32ErrorString());
//Start reading changes in background thread
m_Callback = std::move(a_Callback);
m_Reading = true;
m_ReadThread = std::thread(&CrDirectoryWatcher::StartRead, this);
这是 StartRead()
: (注意: m_Reading
是 atomic<bool>
)
void StartRead()
{
DWORD dwBytes = 0;
FILE_NOTIFY_INFORMATION fni{0};
OVERLAPPED o{0};
//Be sure to set the hEvent member of the OVERLAPPED structure to a unique event.
o.hEvent = CreateEvent(0, 0, 0, 0);
while(m_Reading)
{
if (!ReadDirectoryChangesW(m_hDIR,
&fni, sizeof(fni),
TRUE, FILE_NOTIFY_CHANGE_LAST_WRITE,
&dwBytes, &o, NULL))
{
CrAssert(0, CrWin32ErrorString());
}
if (!GetOverlappedResult(m_hDIR, &o, &dwBytes, FALSE))
CrAssert(0, CrWin32ErrorString());
if (fni.Action != 0)
{
std::wstring fileName(fni.FileName, fni.FileNameLength);
m_Callback(fileName);
fni.Action = 0;
}
}
}
基本上,我在每一帧“轮询”新的变化。现在当我调用 GetOverlappedResult()
它失败并产生以下错误:
Overlapped I/O event is not in a signaled state.
我错过了什么吗?是ReadDirectoryChangesW
意味着被称为每个“滴答声”?或者只是在检测到新变化时?
注意:当我省略 OVERLAPPED
时struct (和 GetOverlappedResult
)它可以工作,但会阻塞线程直到读取更改。这会阻止我的应用程序正确终止。 (即我无法加入线程)
最佳答案
调用GetOverlappedResult()
时,如果将bWait
参数设置为FALSE且I/O操作尚未完成,GetOverlappedResult()
失败,出现 ERROR_IO_INCOMPLETE
错误代码:
bWait [in]
If this parameter isTRUE
, and theInternal
member of thelpOverlapped
structure isSTATUS_PENDING
, the function does not return until the operation has been completed. If this parameter isFALSE
and the operation is still pending, the function returnsFALSE
and theGetLastError
function returnsERROR_IO_INCOMPLETE
.
这不是 fatal error ,因此请忽略该错误并继续。
是的,请确保在 GetOverlappedResult()
报告之前的 I/O 操作已先完成之前,不要再次调用 ReadDirectoryChangesW()
。
话虽如此,您的代码还有另一个问题。您的线程正在堆栈上分配单个 FILE_NOTIFY_INFORMATION
实例。如果您查看 FILE_NOTIFY_INFORMATION
的定义,它的 FileName
字段是可变长度的:
typedef struct _FILE_NOTIFY_INFORMATION {
DWORD NextEntryOffset;
DWORD Action;
DWORD FileNameLength;
WCHAR FileName[1];
} FILE_NOTIFY_INFORMATION, *PFILE_NOTIFY_INFORMATION;
FileName
A variable-length field that contains the file name relative to the directory handle. The file name is in the Unicode character format and is not null-terminated.
这意味着静态分配 FILE_NOTIFY_INFORMATION
会太小,而且 dwBytes
几乎总是 0,因为 ReadDirectoryChangesW()
不会无法向您返回完整的 FILE_NOTIFY_INFORMATION
(除非 FileName
的长度正好是 1 个字符):
When you first call
ReadDirectoryChangesW
, the system allocates a buffer to store change information. This buffer is associated with the directory handle until it is closed and its size does not change during its lifetime. Directory changes that occur between calls to this function are added to the buffer and then returned with the next call. If the buffer overflows, the entire contents of the buffer are discarded, thelpBytesReturned
parameter contains zero, and theReadDirectoryChangesW
function fails with the error codeERROR_NOTIFY_ENUM_DIR
.
ERROR_NOTIFY_ENUM_DIR
1022 (0x3FE)
A notify change request is being completed and the information is not being returned in the caller's buffer. The caller now needs to enumerate the files to find the changes.
因此,您需要动态分配一个大字节缓冲区来接收 FILE_NOTIFY_INFORMATION
数据,然后只要 GetOverlappedResult()
报告数据可用,您就可以遍历该缓冲区。
您的线程应该看起来更像这样:
void StartRead()
{
DWORD dwBytes = 0;
std::vector<BYTE> buffer(1024*64);
OVERLAPPED o{0};
bool bPending = false;
//Be sure to set the hEvent member of the OVERLAPPED structure to a unique event.
o.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!o.hEvent) {
CrAssert(0, CrWin32ErrorString());
}
while (m_Reading)
{
bPending = ReadDirectoryChangesW(m_hDIR,
&buffer[0], buffer.size(),
TRUE, FILE_NOTIFY_CHANGE_LAST_WRITE,
&dwBytes, &o, NULL);
if (!bPending)
{
CrAssert(0, CrWin32ErrorString());
}
while (m_Reading)
{
if (GetOverlappedResult(m_hDIR, &o, &dwBytes, FALSE))
{
bPending = false;
if (dwBytes != 0)
{
FILE_NOTIFY_INFORMATION *fni = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(&buffer[0]);
do
{
if (fni->Action != 0)
{
std::wstring fileName(fni->FileName, fni->FileNameLength);
m_Callback(fileName);
}
if (fni->NextEntryOffset == 0)
break;
fni = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(reinterpret_cast<BYTE*>(fni) + fni->NextEntryOffset);
}
while (true);
}
break;
}
if (GetLastError() != ERROR_IO_INCOMPLETE) {
CrAssert(0, CrWin32ErrorString());
}
Sleep(10);
}
if (bPending)
{
CancelIo(m_hDIR);
GetOverlappedResult(m_hDIR, &o, &dwBytes, TRUE);
}
}
CloseHandle(o.hEvent);
}
在不定期轮询 I/O 状态的情况下实现这一点的另一种方法是摆脱 m_Reading
并改用可等待事件。让操作系统在线程应该调用 GetOverlappedResult()
或终止时向线程发出信号,这样它就可以在不忙于做某事的其余时间休眠:
m_hDIR = CreateFileW(
basePath,
FILE_LIST_DIRECTORY | GENERIC_READ,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
NULL);
if (m_hDIR == INVALID_HANDLE_VALUE)
throw CrException(CrWin32ErrorString());
m_TermEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!m_TermEvent)
throw CrException(CrWin32ErrorString());
//Start reading changes in background thread
m_Callback = std::move(a_Callback);
m_ReadThread = std::thread(&CrDirectoryWatcher::StartRead, this);
...
SetEvent(m_TermEvent);
m_ReadThread.join();
void StartRead()
{
DWORD dwBytes = 0;
std::vector<BYTE> buffer(1024*64);
OVERLAPPED o{0};
bool bPending = false, bKeepRunning = true;
//Be sure to set the hEvent member of the OVERLAPPED structure to a unique event.
o.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!o.hEvent) {
CrAssert(0, CrWin32ErrorString());
}
HANDLE h[2] = {o.hEvent, h_TermEvent};
do
{
bPending = ReadDirectoryChangesW(m_hDIR,
&buffer[0], buffer.size(),
TRUE, FILE_NOTIFY_CHANGE_LAST_WRITE,
&dwBytes, &o, NULL);
if (!bPending)
{
CrAssert(0, CrWin32ErrorString());
}
switch (WaitForMultipleObjects(2, h, FALSE, INFINITE))
{
case WAIT_OBJECT_0:
{
if (!GetOverlappedResult(m_hDIR, &o, &dwBytes, TRUE)) {
CrAssert(0, CrWin32ErrorString());
}
bPending = false;
if (dwBytes == 0)
break;
FILE_NOTIFY_INFORMATION *fni = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(&buffer[0]);
do
{
if (fni->Action != 0)
{
std::wstring fileName(fni->FileName, fni->FileNameLength);
m_Callback(fileName);
}
if (fni->NextEntryOffset == 0)
break;
fni = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(reinterpret_cast<BYTE*>(fni) + fni->NextEntryOffset);
}
while (true);
break;
}
case WAIT_OBJECT_0+1:
bKeepRunning = false;
break;
case WAIT_FAILED:
CrAssert(0, CrWin32ErrorString());
break;
}
}
while (bKeepRunning);
if (bPending)
{
CancelIo(m_hDIR);
GetOverlappedResult(m_hDIR, &o, &dwBytes, TRUE);
}
CloseHandle(o.hEvent);
}
关于c++ - ReadDirectoryChangesW 和 GetOverlappedResult,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43664998/
我想知道特定目录的任何更改文件。所以,我想出了 ReadDirectoryChangesW() 和 FindFirstChangeNotification() - FindNextChangeNoti
最初我被链接到这个调用,这样我就可以记录对某个文件的所有访问并捕获对其的所有更改。 我已经完成了几个例子,但都失败了。甚至是msdn代码无法为我编译。 有人可以为我提供一个小的工作片段来监视文件并记录
我已经设法让 ReadDirectoryChangesW() 为我需要监视的文件夹工作。我正在使用 IO 完成例程,所有更改监视都是由一个线程完成的,该线程除了等待更改和停止信号外什么都不做。一切都很
我想监控指定目录下的修改,获取准确的修改信息。所以我决定使用 ReadDirectoryChangesW()功能。但我想异步使用它,这意味着如果目录中没有更改,我不希望我的工作线程被阻塞。 我该怎么做
简介: 我正在尝试使用 ReadDirectoryChangesW 在一个循环中异步。 下面的片段说明了我正在努力实现的目标: DWORD example() { DWORD error =
我正在使用 ReadDirectoryChangesW基于此 question 异步观察目录更改我实现了一个监视给定目录的函数,但我仍然收到错误消息 GetQueuedCompletionStatus
我使用下一个代码来了解某个文件夹中的文件何时更改: HANDLE hDir = ::CreateFile(path, FILE_LIST_DIRECTORY, FILE_SHARE_READ|FILE
我一直在尝试让 ReadDirectoryChangesW 监视子树的文件更改,但我发现我得到的结果不一致。以下是说明问题的自包含测试用例。当我运行它时,它有时会产生: A : Created C :
我已经阅读了 ReadDirectoryChangesW() 的文档,还看到了 CDirectoryChangeWatcher project ,但都没有说明为什么人们想要异步调用它。我知道 curr
我想递归地观察目录中的所有变化,即如果观察 C:\ 我想接收通知 C:\1.txt C:\A\1.txt 如果我使用启用了 watchSubtree 选项的 ReadDirectoryChanges,
我正在使用 GetQueuedCompletionStatusEx() 和 ReadDirectoryChangesW() 尝试接收对多个文件系统层次结构的更改通知。 我注意到当一次有很多更改时,我会
我正在尝试使用 ReadDirectoryChangesW API 使用 python 在 Windows 上查看目录以创建/删除/重命名更改。这是我的代码,它运行良好: results = win3
我将 ReadDirectoryChangesW (Windows API) 与 GetQueuedCompletionStatus 结合使用。如何检测可能的缓冲区溢出以了解至少一个文件系统更改事件已
我有一个应用程序必须监视特定目录中的任何更改。我使用以下代码,但是当我重命名文件时,不会触发操作 FILE_ACTION_RENAMED_NEW_NAME。实际上,触发了 UNDISCOVERED A
我正在尝试使用 ReadDirectoryChangesW 来跟踪文件创建、复制或移动到受监控目录的时间。 我的问题是,当我在受监控的目录上复制或创建文件时,ReadDirectoryChangesW
使用 ReadDirectoryChangesW 监视文件夹会导致其父级被锁定且无法删除。 这里有一篇关于这个的帖子: FindFirstChangeNotification locks parent
这是名为 JNotify 的开源项目的一部分。我正在尝试修复 Win32 实现,这真的让我抓狂。我已经阅读了 MSDN 中关于此的所有内容,并阅读了有关此糟糕 API 的所有网络帖子。我正在尝试使用完
我这样做对吗? 我正在尝试查找在名为 C:\Perl 的文件夹中发生的所有更改 在 ReadDirectoryChangesW 之后,它就卡在那里了。它没有前进。我是否遗漏了一些明显的东西? 我正在努
我调用 ReadDirectoryChangesW异步监视后台线程中的目录更改。 这是如何打开目录 ( basePath) 并启动“读取”线程的: m_hDIR = CreateFileW(
我想在一个线程中实时监控几个目录的变化,所以我决定使用与GetQueuedCompletionStatus异步的ReadDirectoryChangesW()方法。这是我的代码: static DWO
我是一名优秀的程序员,十分优秀!