2013-03-08 2 views
4

У меня есть наблюдатель kQueue в каталоге Documents в моем приложении. Я использую kQueue, который вызывает обратный вызов, когда изменяется содержимое каталога документов.kQueue monitoring monitoring

здесь две настройки

eventToAdd.flags = EV_ADD | EV_CLEAR; 
eventToAdd.fflags = NOTE_WRITE; 

Проблема заключается в том, что я получаю уведомление, когда содержимое изменилось, когда добавляется новый файл, но сам файл еще не полностью скопировали, поэтому, когда я пытаюсь процесс в новом файле я получаю сбой SIGABRT.

Как я могу отложить уведомление до тех пор, пока файл не будет завершен?

ответ

2

Я решил это, создав 2 прослушивателя ... один в каталоге документов приложения для просмотра новых файлов и объект прокси-файла, который создается для каждого отображаемого файла. Объект File имеет флаг fileBusy. Объект File устанавливает 2-секундный таймер, когда в файл записывается фрагмент данных. Я предполагаю, что файл полностью написан, если никаких обновлений до истечения срока действия таймера.

файл коды изменения слушателя здесь: https://gist.github.com/nielsbot/5155671

Мой (частичный) делегат для приведенного выше слушателя ниже. (Объект «Файл», который представляет файл на диске)

@implementation File<FileChangeObserverDelegate> 

    -(void)scheduleFileBusyTimeout 
    { 
     self.fileBusyTimeoutTimer = [ NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(fileBusyTimeoutTimerFired:) userInfo:nil repeats:NO ] ; 
    } 

    -(void)setFileChangeObserver:(FileChangeObserver *)observer 
    { 
     [_fileChangeObserver invalidate ] ; 
     _fileChangeObserver = observer ; 
    } 

    -(void)fileChanged:(FileChangeObserver *)asset typeMask:(enum FileChangeNotificationType)type 
    { 
     @synchronized(self) 
     { 
      if ((type & kFileChangeType_Delete) != 0) 
      { 
       // we're going away soon... 
       self.fileChangeObserver = nil ; 
      } 
      else 
      { 

       self.fileBusy = YES ; 
       [ self scheduleFileBusyTimeout ] ; 
      } 
     } 
    } 

    -(void)fileBusyTimeoutTimerFired:(NSTimer*)timer 
    { 
     @autoreleasepool { 
      self.fileBusy = NO ; 
     } 
    } 

    -(void)setFileBusyTimeoutTimer:(NSTimer *)timer 
    { 
     [ _fileBusyTimeoutTimer invalidate ] ; 
     _fileBusyTimeoutTimer = timer ; 
    } 
@end 
+0

Спасибо за это. Я попробую скоро и вернусь к вам. – jarryd

0

Во-первых, см:

Короткий ответ: нет отличного способа сделать это. В идеале вы должны написать файл в другом месте, а затем переместить его в Документы. Это делает его атомным действием. Или напишите его как специальное имя файла («.partial», «.download» и т. Д.) И переименуйте его в конце (опять-таки, атомное действие, которое будет запускать второе событие kqueue).

+0

Мне нравится концепция '.partial' - хотя если вы отбрасываете файлы через iTunes, она не будет подчиняться этому правилу. Мое обходное решение состояло в том, чтобы установить таймер после записи каждого файла, а затем предположить, что файл полностью записан после 1 или более раз. – nielsbot

+0

@nielsbot - достаточно 1 секунды? Не активируется ли событие при добавлении имени файла, и в зависимости от размера файла операция записи является динамической, и время не может быть известно. – jarryd

+0

вы получите уведомление об kqueue каждый раз, когда в файл записывается _new chunk_. - Сбросьте свой таймер на 1 с после _each chunk_. Таймер 1s не предназначен для записи всего файла. Если никакие куски не записываются в течение 1 с, предположим, что файл полностью написан. Не знаю, я знаю, но я не мог придумать лучшего способа. – nielsbot