How to monitor a folder for new files in swift?

前端 未结 10 1996
既然无缘
既然无缘 2020-12-23 17:17

How would I monitor a folder for new files in swift, without polling (which is very inefficient)? I\'ve heard of APIs such as kqueue and FSEvents - but I\'m not sure it\'s p

相关标签:
10条回答
  • 2020-12-23 17:45

    I faced a problem that is not mentioned in any of the answers. As my app is using a UIDocumentBrowserViewController (i.e. Apple's own Files app) to manage its documents, I have no control over my users' habits. I was using SKQueue to monitor all files in order to keep metadata in sync, and at a certain point the app started crashing.

    As it turns out, there is an upper limit of 256 file descriptors that can be open by an app simultaneously, even just for monitoring. I ended up combining SKQueue and Apple's Directory Monitor (reference to which you can find in this answer of the current thread) to create a class I named SFSMonitor, which monitors a whole queue of files or directories by using Dispatch Sources.

    I detailed my findings and the practices I now use in this SO thread.

    0 讨论(0)
  • 2020-12-23 17:50

    You could add UKKQueue to your project. See http://zathras.de/angelweb/sourcecode.htm it's easy to use. UKKQueue is written in Objective C, but you can use it from swift

    0 讨论(0)
  • 2020-12-23 17:50

    Depending on your application needs, you may be able to use a simple solution.

    I actually used kqueue in a production product; I wasn't crazy with the performance but it worked, so I didn't think too much of it till I found a nice little trick that worked even better for my needs, plus, it used less resources which can be important for performance intensive programs.

    What you can do, again, if your project permits, is that every time you switch to your application, you can just check the folder as part of your logic, instead of having to periodically check the folder using kqueue. This works and uses far less resources.

    0 讨论(0)
  • 2020-12-23 17:52

    I adapted Stanislav Smida's code to make it work with Xcode 8 and 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()
      }
    
    }
    
    0 讨论(0)
  • 2020-12-23 17:52

    The simplest solution is to use Apple's 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()
    
    0 讨论(0)
  • 2020-12-23 17:54

    I've tried to go with these few lines. So far seems to work.

    class DirectoryObserver {
    
        deinit {
    
            dispatch_source_cancel(source)
            close(fileDescriptor)
        }
    
        init(URL: NSURL, block: dispatch_block_t) {
    
            fileDescriptor = open(URL.path!, O_EVTONLY)
            source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, UInt(fileDescriptor), DISPATCH_VNODE_WRITE, dispatch_queue_create(nil, DISPATCH_QUEUE_CONCURRENT))
            dispatch_source_set_event_handler(source, { dispatch_async(dispatch_get_main_queue(), block) })
            dispatch_resume(source)
        }
    
        //
    
        private let fileDescriptor: CInt
        private let source: dispatch_source_t
    }
    

    Be sure to not get into retain cycle. If you are going to use owner of this instance in block, do it safely. For example:

    self.directoryObserver = DirectoryObserver(URL: URL, block: { [weak self] in
    
        self?.doSomething()
    })
    
    0 讨论(0)
提交回复
热议问题