如何在swift中监视新文件的文件夹?

use*_*570 26 macos swift

如何在没有轮询的情况下在swift中监视新文件的文件夹(这是非常低效的)?我听说过像kqueue和FSEvents这样的API - 但我不确定是否可以在swift中实现它们?

Eon*_*nil 12

GCD似乎是要走的路.NSFilePresenter类无法正常工作.他们是马车,破损,苹果过去4年不愿意修理它们.可能会被弃用.

这是一篇非常好的帖子,描述了这种技术的基本要素.

"使用GCD处理文件系统事件",作者:David Hamrick.

网站引用的示例代码.我将他的C代码翻译成Swift.

    let fildes = open("/path/to/config.plist", O_RDONLY)

    let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
    let source = dispatch_source_create(
        DISPATCH_SOURCE_TYPE_VNODE,
        UInt(fildes),
        DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_EXTEND | DISPATCH_VNODE_ATTRIB | DISPATCH_VNODE_LINK | DISPATCH_VNODE_RENAME | DISPATCH_VNODE_REVOKE,
        queue)

    dispatch_source_set_event_handler(source,
        {
            //Reload the config file
        })

    dispatch_source_set_cancel_handler(source,
        {
            //Handle the cancel
        })

    dispatch_resume(source);

    ...

        // sometime later
        dispatch_source_cancel(source);
Run Code Online (Sandbox Code Playgroud)

作为参考,这是作者发布的另一个QA:


如果你对观看目录感兴趣,这里有另一篇描述它的帖子.

"监视文件夹GCD"Cocoanetics.(不幸的是,我找不到作者的名字.我很遗憾没有归属)

唯一明显的区别是获取文件描述符.这使得目录的仅事件通知文件描述符成为可能.

_fileDescriptor = open(path.fileSystemRepresentation(), O_EVTONLY)
Run Code Online (Sandbox Code Playgroud)

更新

以前我声称FSEventsAPI不起作用,但我错了.API工作得非常好,如果你对在深层文件树上观看感兴趣,那么它比GCD更简单.

无论如何,FSEvents不能用于纯Swift程序.因为它需要传递C回调函数,而Swift目前不支持它(Xcode 6.1.1).然后我不得不回到Objective-C并再次包装它.

此外,任何此类API都是完全异步的.这意味着在您收到通知时,实际的文件系统状态可能会有所不同.然后精确或准确的通知实际上没有用,并且仅用于标记脏标志.

更新2

我最终FSEvents为Swift 编写了一个包装器.这是我的工作,我希望这会有所帮助.


mdo*_*ati 6

我修改了斯坦尼斯拉夫·斯米达(Stanislav Smida)的代码,使其可以与Xcode 8和Swift 3一起使用

class DirectoryObserver {

    private let fileDescriptor: CInt
    private let source: DispatchSourceProtocol

    deinit {

      self.source.cancel()
      close(fileDescriptor)
    }

    init(URL: URL, block: @escaping ()->Void) {

      self.fileDescriptor = open(URL.path, O_EVTONLY)
      self.source = DispatchSource.makeFileSystemObjectSource(fileDescriptor: self.fileDescriptor, eventMask: .all, queue: DispatchQueue.global())
      self.source.setEventHandler { 
          block()
      }
      self.source.resume()
  }

}
Run Code Online (Sandbox Code Playgroud)


imi*_*ike 5

最简单的解决方案是使用Apple的DirectoryMonitor.swift https://developer.apple.com/library/mac/samplecode/Lister/Listings/ListerKit_DirectoryMonitor_swift.html

var dm = DirectoryMonitor(URL: AppDelegate.applicationDocumentsDirectory)
dm.delegate = self
dm.startMonitoring()
Run Code Online (Sandbox Code Playgroud)

  • Swift 3 版本镜像于:https://github.com/robovm/apple-ios-samples/blob/master/ListerforwatchOSiOSandOSX/Swift/ListerKit/DirectoryMonitor.swift (2认同)

Edw*_*eer 0

您可以将 UKKQueue 添加到您的项目中。请参阅http://zathras.de/angelweb/sourcecode.htm,它很容易使用。UKKQueue 是用 Objective C 编写的,但您可以在 swift 中使用它