NSFileManager watch directory

主宰稳场 提交于 2019-11-30 10:23:46

Look Kernel Queues: An Alternative to File System Events in Apple documentation. There is an example for iOS in AVPlayerDemo (look DirectoryWatcher class).

Also, check Directory Monitor blog post.

Here's my version of DirectoryWatcher written in Swift using GCD instead of Mach and using a closure instead of a delegate

import Foundation

@objc public class DirectoryWatcher : NSObject {
    override public init() {
        super.init()
    }

    deinit {
        stop()
    }

    public typealias Callback = (_ directoryWatcher: DirectoryWatcher) -> Void

    @objc public convenience init(withPath path: String, callback: @escaping Callback) {
        init()
        if !watch(path: path, callback: callback) {
            assert(false)
        }
    }

    private var dirFD : Int32 = -1 {
        didSet {
            if oldValue != -1 {
                close(oldValue)
            }
        }
    }
    private var dispatchSource : DispatchSourceFileSystemObject?

    @objc public func watch(path: String, callback: @escaping Callback) -> Bool {
        // Open the directory
        dirFD = open(path, O_EVTONLY)
        if dirFD < 0 {
            return false
        }

        // Create and configure a DispatchSource to monitor it
        let dispatchSource = DispatchSource.makeFileSystemObjectSource(fileDescriptor: dirFD, eventMask: .write, queue: DispatchQueue.main)
        dispatchSource.setEventHandler {[unowned self] in
            callback(self)
        }
        dispatchSource.setCancelHandler {[unowned self] in
            self.dirFD = -1
        }
        self.dispatchSource = dispatchSource

        // Start monitoring
        dispatchSource.resume()

        // Success
        return true
    }

    @objc public func stop() {
        // Leave if not monitoring
        guard let dispatchSource = dispatchSource else {
            return
        }

        // Don't listen to more events
        dispatchSource.setEventHandler(handler: nil)

        // Cancel the source (this will also close the directory)
        dispatchSource.cancel()
        self.dispatchSource = nil
    }
}

Use it like Apple's DirectoryWatcher example, something like this:

let directoryWatcher = DirectoryWatcher(withPath: "/path/to/the/folder/you/want/to/monitor/", callback: {
    print("the folder changed")
})

Destroying the object will stop watching, or you can stop it explicitly

directoryWatcher.stop()

It should be compatible with Objective C they way it's written (untested). Using it would be like this:

DirectoryWatcher *directoryWatcher = [DirectoryWatcher.alloc initWithPath: @"/path/to/the/folder/you/want/to/monitor/" callback: ^(DirectoryWatcher *directoryWatcher) {
    NSLog(@"the folder changed")
}];

Stopping it is similar

[directoryWatcher stop];
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!