4

我的应用程序的 Documents 目录中有一个 kQueue 观察者。我正在使用在 Documents 目录内容更改时触发回调的 kQueue。

这是其中的两个设置

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

问题是当添加新文件时内容发生更改时我会收到通知,但实际文件尚未完全复制,所以当我尝试处理新文件时,我会遇到 SIGABRT 崩溃。

如何延迟通知直到文件完成?

4

2 回答 2

2

我通过创建 2 个侦听器解决了这个问题……一个在应用程序的 Documents 目录上以监视出现的新文件,以及为每个出现的文件创建的 File 代理对象。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
于 2013-03-13T21:38:09.997 回答
0

首先,请看:

简短的回答是没有很好的方法来做到这一点。理想情况下,您应该将文件写入其他位置,然后将其移至 Documents。这使它成为一个原子动作。或者把它写成一个特殊的文件名(“.partial”、“.download”等)并在最后重命名(同样,一个原子动作会触发第二个 kqueue 事件)。

于 2013-03-13T19:41:20.157 回答