RxFileMonitor
RxSwift 对 CoreFoundation 文件系统事件的 Observable
包装。
示例应用程序可以作为始终位于最前面的浮动文件事件日志。启动应用程序,选择一个目录,选择 窗口 > 总是最前方,享受事件的涌入。您还可以使用 ⌘K 清除记录的消息。
使用方法
您在一个文件夹上设置了 FolderContentMonitor
并将收到有关 ...
- 文件夹本身的更改通知,和
- 它内部任何项目的更改(不包括子文件夹)。
它通过 .rx.folderContentChange
提供了方便的响应式扩展。
示例
import RxFileMonitor
let disposeBag = DisposeBag()
let folderUrl = URL(fileURLWithPath: "/path/to/monitor/")
// Keep this strongly referenced/alive
let monitor = FolderContentMonitor(url: folderUrl)
monitor.rx.folderContentChange
.subscribe(onNext: { event in
print("Folder contents changed at \(event.url) (\(event.change))")
})
.disposed(by: disposeBag)
仅响应文件内容更改
假设您想更新一个文件夹中笔记内容的缓存,您将只对文件感兴趣
self.monitor = FolderContentMonitor(url: folderUrl)
let changedFile = self.monitor.rx.folderContentChange
// Files only ...
.filter { $0.change.contains(.isFile) }
// ... except the user's folder settings.
.filter { $0.filename != ".DS_Store" }
.map { $0.filename }
.observeOn(MainScheduler.instance)
.disposed(by: disposeBag)
现在您将想要更新更改文件的缓存
changedFile.subscribe(onNext: cache.updateFile)
或者如果您在有任何更改时简单地重建整个缓存,您可以在过滤出接受事件后停止
// Keep this strongly references
self.monitor = FolderContentMonitor(url: folderUrl)
let changedFile = self.monitor.rx.folderContentChange
.filter { $0.change.contains(.isFile) }
.filter { $0.filename != ".DS_Store" }
.observeOn(MainScheduler.instance)
.subscribe(onNext: { _ in
cache.rebuild()
})
关于延迟的注释
0.0(默认值)的延迟可能会产生过多的噪声。尝试使用略高值,以便系统可以在适当的时候合并事件。
当你运行示例应用来查看哪些类型的事件被触发时,请确保使用TextEdit创建和修改文件,以便您可以看到哪些类型的事件会被绑定。这里是带注释的日志:
// Create file in folder
texteditfile.txt changed (isFile, renamed, xattrsModified)
texteditfile.txt changed (isFile, renamed, finderInfoModified, xattrsModified)
// Save changes to file
texteditfile.txt changed (isFile, renamed, finderInfoModified, xattrsModified)
texteditfile.txt.sb-56afa5c6-DmdqsL changed (isFile, renamed)
texteditfile.txt changed (isFile, renamed, finderInfoModified, xattrsModified)
texteditfile.txt changed (isFile, renamed, finderInfoModified, inodeMetaModified, xattrsModified)
texteditfile.txt.sb-56afa5c6-DmdqsL changed (isFile, modified, removed, renamed, changeOwner)
texteditfile.txt changed (isFile, renamed, finderInfoModified, inodeMetaModified, xattrsModified)
您会看到在像TextEdit这样的现代基于文档的macOS应用中使用原子方式覆盖文件时,将触发大量事件。作者对这些事件的理解是:“删除原始文件,将带有更改的临时文件移动进去,将临时文件复制到原始文件路径,然后删除临时文件”。根据我的了解,这可能意味着原始文件被重命名为临时看起来像的名字。当然,可能了解得不太多。(大概就是这样。)
现在看相同操作的1秒延迟的日志:
// Create file in folder
texteditfile.txt changed (isFile, renamed, finderInfoModified, xattrsModified)
// Save changes to file
texteditfile.txt changed (isFile, renamed, finderInfoModified, xattrsModified)
texteditfile.txt.sb-56afa5c6-SOiDRl changed (isFile, renamed)
texteditfile.txt changed (isFile, renamed, finderInfoModified, inodeMetaModified, xattrsModified)
texteditfile.txt.sb-56afa5c6-SOiDRl changed (isFile, modified, removed, renamed, changeOwner)
(这已经是最棒的改进了。)
因此,可能略大于>0.0的延迟可以帮助消除噪声。当你最终合并RxSwift.Observable
事件时,这更加合理。
请注意,其他编辑器如TextMate 2不使用相同的机制向文件写入,并且只生成单个事件,类似于从shell发起的文件更改所期望的那样。
texteditfile.txt changed (isFile, modified, xattrsModified)
事件解释
看看仓库的问题 -- 仍然有很多改进的空间。这归结为应用解释和启发式法。换句话说,它可能出错或完全错误。
目前,每个FSEvent都会转发到回调(或观察者)。
FSEvents有时会成对出现,比如
texteditfile.txt changed (isFile, renamed, finderInfoModified, xattrsModified)
texteditfile.txt.sb-56afa5c6-SOiDRl changed (isFile, renamed)
这意味着库可以尝试理解事件对并将其简化为单个事件供客户端使用。而不是转发一个形式为"texteditfile.txt.sb-56afa5c6-SOiDRl
已重命名"的事件,这在客户端术语中将被解释为“文件已被移动那里”,库可以触发一个单独的"已编辑"事件。
也值得注意:在Finder中从回收站中删除文件时不会触发removed
事件,尽管在TextEdit保存文件更改并删除中间结果文件时触发了事件。因此,一些renamed
事件实际上是removed
事件,并且您需要在事件到来后检查URL上的文件是否存在。有了某种延迟,否则您可能会在文件移动完成之前抓取即将被删除的文件。
许可证
版权所有(c)2016 RxSwiftCommunity https://github.com/RxSwiftCommunity
在The MIT许可证下分发
在此特此授予任何获得本软件及其相关文档副本(以下称为“软件”)的人免费权利,无任何限制地处理该软件,包括无限制使用、复制、修改、合并、发布、分发、再许可和/或出售软件副 本,并允许向软件提供方提供软件的人这样做,前提是遵守以下条件
上述版权声明和此许可声明应包含在本软件的所有副本或主要部分中。
软件按“原样”提供,不提供任何性质的保证,明示或暗示,包括但不限于对适销性、针对特定目的的适宜性和非侵权的保证。在任何情况下,作者或版权持有人对任何诉求、损害或其他责任,无论在合同、侵权或其他法律依据下产生,均不承担责任,无论该损害或责任与软件或其使用或其他方式有关。