[英]File system watcher for Mac OS X
目前,我們使用屬於Qt的QFileSystemWatcher。 由於Mac OS X中的支持有限,它只能通知我們兩個事件:目錄已更改或文件已更改。
但是,后一個事件(文件已更改)會在其大小稍大時觸發多次,並且寫入磁盤需要稍長的時間。
我們的解決方法是設置一個計時器來在1秒內檢查文件。 如果在計時器到期之前有關於該文件的更多信號,我們重置計時器。
有沒有辦法在文件寫入磁盤時獲得通知(完成寫入)? 沒有必要限制Qt,任何庫都可以。
我們知道kqueue監控方法,但是這個級別太低了,我們不希望為每個文件執行此操作,因為我們正在監視文件系統的大部分內容。
我在項目中遇到同樣的問題,最后我決定實現一個本地觀察者。 這很簡單:
在.h:
class OSXWatcher : public Watcher
{
public:
OSXWatcher(const QString& strDirectory);
virtual ~OSXWatcher();
virtual bool Start();
virtual bool Stop();
private:
/**
* Callback function of the OS X FSEvent API.
*/
static void fileSystemEventCallback(ConstFSEventStreamRef streamRef, void *clientCallBackInfo, size_t numEvents, void *eventPaths, const FSEventStreamEventFlags eventFlags[], const FSEventStreamEventId eventIds[]);
FSEventStreamRef stream;
};
.cpp:
bool OSXWatcher::Start()
{
CFStringRef pathToWatchCF = CFStringCreateWithCString(NULL, this->dirToWatch.toUtf8().constData(), kCFStringEncodingUTF8);
CFArrayRef pathsToWatch = CFArrayCreate(NULL, (const void **)&pathToWatchCF, 1, NULL);
FSEventStreamContext context;
context.version = 0;
context.info = this;
context.retain = NULL;
context.release = NULL;
context.copyDescription = NULL;
stream = FSEventStreamCreate(NULL, &OSXWatcher::fileSystemEventCallback, &context, pathsToWatch, kFSEventStreamEventIdSinceNow, 3.0, kFSEventStreamCreateFlagFileEvents);
FSEventStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
FSEventStreamStart(stream);
CFRelease(pathToWatchCF);
// Read the folder content to protect any unprotected or pending file
ReadFolderContent();
}
bool OSXWatcher::Stop()
{
FSEventStreamStop(stream);
FSEventStreamInvalidate(stream);
FSEventStreamRelease(stream);
}
void OSXWatcher::fileSystemEventCallback(ConstFSEventStreamRef /*streamRef*/, void *clientCallBackInfo, size_t numEvents, void *eventPaths, const FSEventStreamEventFlags eventFlags[], const FSEventStreamEventId eventIds[])
{
char **paths = (char **)eventPaths;
for (size_t i=0; i<numEvents; i++) {
// When a file is created we receive first a kFSEventStreamEventFlagItemCreated and second a (kFSEventStreamEventFlagItemCreated & kFSEventStreamEventFlagItemModified)
// when the file is finally copied. Catch this second event.
if (eventFlags[i] & kFSEventStreamEventFlagItemCreated
&& eventFlags[i] & kFSEventStreamEventFlagItemModified
&& !(eventFlags[i] & kFSEventStreamEventFlagItemIsDir)
&& !(eventFlags[i] & kFSEventStreamEventFlagItemIsSymlink)
&& !(eventFlags[i] & kFSEventStreamEventFlagItemFinderInfoMod)) {
OSXWatcher *watcher = (OSXWatcher *)clientCallBackInfo;
if (watcher->FileValidator(paths[i]))
emit watcher->yourSignalHere();
}
}
}
我有同樣的問題,但有文件夾。 當您將許多文件復制到文件夾時,會發出太多的信號,但我只需要一個。 所以我有以下解決方案:
void folderChanged(const QString& folder)
{
m_pTimerForChanges->start();
}
folderChanged
是directoryChanged()
信號的插槽。 並且計時器有另一個超時連接,所以當時間結束時,應該進行處理。 定時器有1s間隔。 它背后的想法是文件夾不應該比我的間隔更頻繁地更新,如果它比我需要更頻繁地發送信號,那么我不需要立即處理它們。 更確切地說,每次信號發出時我都會重新啟動計時器,所有這些都是我唯一一次處理的變化。 我認為你可以采用相同的方法。
另一種可能對你有用的方法是檢查你的處理中的文件修改日期,如果它的當前修改日期在你上次修改日期的某個epsilon(小間隔)內,那么你有重復的信號,不應對它作出反應。 存儲此修改日期並繼續。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.