Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
FileWatcher / FileListener
import Foundation
fileprivate let queue = DispatchQueue(label: "FileMonitorQueue", target: .main)
enum FileWatcherError: Error {
case directoryOpenFailed(Int32)
case directoryURLInvalid(URL)
}
final class FileWatcher {
let fsSource: DispatchSourceFileSystemObject
var readSource: DispatchSourceRead!
init(in directory: URL, filename: String, errorHandler: ((Error) -> Void)?) throws {
let fileDescriptor: Int32 = try directory.withUnsafeFileSystemRepresentation { path in
guard let path = path else { throw FileWatcherError.directoryURLInvalid(directory) }
let result = open(path, O_EVTONLY)
guard result >= 0 else { throw FileWatcherError.directoryOpenFailed(errno) }
return result
}
fsSource = DispatchSource.makeFileSystemObjectSource(
fileDescriptor: fileDescriptor,
eventMask: .write,
queue: queue
)
fsSource.setEventHandler { [unowned self] in
do {
let fileHandle = try FileHandle(
forReadingFrom: directory.appendingPathComponent(filename)
)
self.readSource = DispatchSource.makeReadSource(fileDescriptor: fileHandle.fileDescriptor, queue: queue)
self.readSource.setEventHandler {
fileHandle.readToEndOfFileInBackgroundAndNotify()
}
self.readSource.resume()
self.readSource.setCancelHandler {
fileHandle.closeFile()
}
} catch {
errorHandler?(error)
}
}
fsSource.setCancelHandler {
close(fileDescriptor)
}
fsSource.resume()
}
deinit {
fsSource.cancel()
}
}
final class FileListener {
init() {
NotificationCenter.default.addObserver(
self,
selector: #selector(handler),
name: .NSFileHandleReadToEndOfFileCompletion,
object: nil
)
}
@objc func handler() {
/* file is available for reading here */
}
}
@DevyV
Copy link

DevyV commented May 6, 2020

Sid,

I solved it myself :)
I needed to change line 26 from:

eventMask: .write,

to

eventMask: .all,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment