2013-03-04 6 views
1

В настоящее время мы используем QFileSystemWatcher, принадлежащий Qt. Из-за ограниченной поддержки в Mac OS X он может только уведомлять нас обо всех событиях: каталог изменен или файл изменен.Наблюдатель файловой системы для Mac OS X

Однако последнее событие (файл изменено) запускается несколько раз, когда его размер немного больше, а запись на диск занимает немного больше времени.

Наше обходное решение - установить таймер для проверки файла за 1 секунду. Если до истечения времени истечения таймера появляется больше сигналов о файле, мы перезапускаем таймер.

Есть ли способ получить уведомление, когда файл записан на диск (закончил запись)? Нет необходимости ограничивать Qt, любая библиотека могла бы сделать.


Мы знаем о методе мониторинга Kqueue, но это слишком низкий уровень, и мы не хотим, чтобы сделать это для каждого файла, как мы отслеживаем большую часть файловой системы ..

+0

QFileWatcher посылает сигнал fileChange постоянно в то время как файл записывается на диск или только один раз, когда он начинает письмо? – ixSci

+0

@ixSci постоянно посылает сигалы; сигналы были обмануты даже для небольших файлов. – zzk

ответ

1

У меня такая же проблема, но с папкой. Когда вы копируете много файлов в папку, слишком много синглов испускаются, но мне нужно только одно. Поэтому у меня есть следующее решение:

void folderChanged(const QString& folder) 
{ 
    m_pTimerForChanges->start(); 
} 

folderChanged слот для directoryChanged() сигнала. И таймер имеет другое соединение для тайм-аута, поэтому, когда время не работает, обработка должна быть выполнена. Таймер имеет интервал 1 с. Идея заключается в том, что папка не должна обновляться чаще, чем интервал, который у меня есть, и если он посылает сигналы чаще, чем мне нужно, мне не нужно немедленно их обрабатывать. Скорее, я запускаю таймер каждый раз, когда сигнал передается, и со всем этим у меня есть только одна обработка изменений. Я думаю, вы можете применить тот же подход.

Другим подходом, который может работать на вас, также является проверка даты изменения файла в вашей обработке, и если его текущая дата изменения находится в пределах некоторого epsilon (небольшой интервал) с вашей последней датой модификации, тогда вы повторяете сигнал и не должны реагировать на Это. Сохраните эту дату изменения и продолжите.

+0

Это в основном аналогичный подход, как мы это делали прямо сейчас. В основном, когда мы получаем сигнал для файла, мы устанавливаем таймер, чтобы проверить его на 1 секунду позже. Если поступит другой сигнал, мы сбросим таймер. Поэтому мы также обрабатываем изменения только один раз. Но то, что нам не нравится, это «произвольное» значение времени и «ненужная» задержка, вызванная таймером .. хотя это может быть и не так важно. – zzk

+0

Я считаю, что Qt использует какой-то системный способ получения уведомления о каких-либо изменения. Следовательно, вы должны использовать какой-то приблизительный подход, так как я сомневаюсь, что есть более точный способ сделать это даже с помощью простого API системы. Также я рекомендую попробовать метод с сопоставлением даты модификации. Я думаю, что он должен работать для изменений файла (например, если файл был изменен в течение 500 мс, тогда он является частью одного целого изменения, а не другого). – ixSci

2

У меня такая же проблема в проекте, и, наконец, я решил реализовать собственный наблюдатель. Это довольно просто:

В .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(); 
     } 
    } 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^