在 Objective-C 中观察文件或文件夹

发布于 2024-08-04 10:45:53 字数 42 浏览 4 评论 0原文

侦听文件夹或文件以查看其是否已保存或是否已添加新文件的最佳方法是什么?

What is the best way to listen to a folder or file to see if it has been saved or if a new file has been added?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

橘亓 2024-08-11 10:45:53

如果您只想监视目录但不处理单个文件的监视,那么 FSEvents API 是理想的选择。 Stu Connolly 有一个很棒的 FSEvents C API 的 Objective-C 包装器,称为 SCEvents,您可以在这里获取它:

http://stuconnolly.com/blog/scevents-011/

FSEvents 的好处是您只需要监视一个文件夹,您就会收到该子文件夹层次结构中任何位置发生的任何更改的通知文件夹。

如果您需要文件级通知,则需要使用 kqueues。 Uli Kusterer 有一个很棒的 Objective-C 包装器:

http://zathras.de/angelweb/sourcecode.htm #UKKQueue

这两种方法都比直接使用 C API 容易得多,C API 没有特别详细的文档记录,而且有点迟钝。

如果您需要支持 Tiger,则需要使用 kqueues,因为 FSEvents API 在 10.4 中尚未正式提供。

The FSEvents API is ideal if you just want to watch directories but it doesn't handle the monitoring of individual files. Stu Connolly has a great Objective-C wrapper for the FSEvents C API, it's called SCEvents and you can get it here:

http://stuconnolly.com/blog/scevents-011/

The nice thing about FSEvents is that you just need to watch one folder and you will be notified of any changes that occur anywhere in the subfolder hierarchy of that folder.

If you need file-level notifications you will need to use kqueues. Uli Kusterer has a great Objective-C wrapper:

http://zathras.de/angelweb/sourcecode.htm#UKKQueue

Either of these methods is a lot easier than wrangling with the C APIs directly, which are not particularly well documented and a bit obtuse.

If you need to support Tiger you'll need to use kqueues as the FSEvents API wasn't officially available in 10.4.

笑看君怀她人 2024-08-11 10:45:53

尝试使用 FSEvents,尽管它是 C API

OS 10.5 或更高版本

Try using FSEvents, although it is a C API

OS 10.5 or newer

可爱咩 2024-08-11 10:45:53

如果您确实需要使用 kqueue (如其他答案中所述)Google Toolbox for Mac 有 不错的 Objective-C 包装器,到目前为止我使用过没有任何问题。

If you do need to use kqueue (as discussed in other answers) Google Toolbox for Mac has a nice Objective-C wrapper that I've used with no issues thus far.

╰沐子 2024-08-11 10:45:53

现在,您可以使用 GCD (Grand Central Dispatch) 来监视文件夹。您也许可以使用相同的技术来监视文件,但即使它仅适用于文件夹,您也可以记下文件的修改日期,并在每次文件夹更改时检查更改。

这是我编写的一个 Swift 类,用于使用 GCD 监视文件夹:

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) {
        self.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
    }
}

像 Apple 的 DirectoryWatcher 示例一样使用它,如下所示:

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

销毁对象将停止监视,或者您可以显式停止它

directoryWatcher.stop()

它应该与 Objective C 兼容,它们的编写方式(未经测试) )。使用它会像这样:

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

停止它是类似的

[directoryWatcher stop];

Nowadays you can use GCD (Grand Central Dispatch) to monitor folders. You might be able to use the same technique for monitoring a file, but even if it only works on folders you can note the modification date of the file and check for changes each time the folder changes.

Here's a Swift class I wrote to monitor a folder using GCD:

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) {
        self.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];
戏舞 2024-08-11 10:45:53

如果您要更改文件或文件夹,我相信 Spotlight 搜索引擎将更新其数据库以反映您的更改。

因此,您可以设置一个线程来侦听 kMDQueryDidUpdateNotification 通过 针对该文件或文件夹的 Spotlight 查询

当您收到这些通知时,您可以触发一个选择器来执行您想要的操作。

If you are changing a file or folder, I believe the Spotlight search engine will update its database to reflect your changes.

So you might set up a thread that listens for kMDQueryDidUpdateNotification notifications through a Spotlight query specific to that file or folder.

When you get those notifications, you could fire a selector that does something you want.

独夜无伴 2024-08-11 10:45:53

不确定什么是最好的方法,但一种方法是启动一个 NSThread,它会定期(例如每秒)检查目录中文件的创建日期,然后让一个与该线程关联的委托来执行某些操作添加新文件时

Not sure what's the best way, but A way would be to fire up an NSThread that would regularly (for instance every second) check the creation dates of the files in the directory, and then have a delegate associated with that thread to perform some action when a new file has been added

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文