kqueue助力:macOS文件更改检测技术新探索 【导语作者为满足文件监控需求开发了小型文件监控器reload最初使用fsnotify包后深入研究其底层的kqueue事件通知接口介绍了kqueue数据结构、监控文件和目录的方法及Go语言实现还探讨了不同文件监控方法。】kqueue文件监控的新利器作者为方便在修改C文件时重新编译、重建并重新加载静态网站开发了小型文件监控器reload。最初使用fsnotify包检测文件更改后因想了解其底层原理将目光投向了macOS上使用的kqueue事件通知接口。kqueue()函数调用会创建一个新的内核事件队列并返回一个文件描述符。使用kevent()函数调用注册并等待系统事件其使用的kevent数据结构有五个关键字段包括ident、filter、flags、fflags和udata。对于文件更改监控内核过滤器选用EVFILT_VNODEfflags使用NOTE_WRITE标志flags使用EV_ADD和EV_CLEAR。精准监控指定文件与目录在监控指定文件时使用O_EVTONLY打开要监控的文件创建kevent结构体数组使用EV_SET宏初始化。通过调用kevent()注册事件然后启动事件循环监听文件更改。完整代码可在GitHub Gist中找到。监控目录时先打开目录本身但仅这样无法监控现有文件的更改还需打开目录中的所有文件并分别监控。当创建新文件时要将其添加到监控列表中。Go语言实现高效与便捷在Go语言中实现时定义了watcher结构体包含kq、fds和fdPaths字段。创建kqueue时调用CloseOnExec避免子进程继承不必要的文件描述符。添加要监控的文件时打开文件并在kqueue上注册文件写入事件。添加目录中的所有文件时遍历目录树并调用Add方法。设置事件循环监听文件事件收到事件后返回更改文件的文件名。当文件事件来自目录时重新遍历目录以添加新文件。方法对比各有优劣除了使用kqueue解决文件监控问题还可采用简单的轮询方式但这种方式效率较低。kqueue为每个被监控的文件都需要一个打开的fd对于非常大的目录树可能无法很好地扩展。在macOS上还可使用FSEvents它不存在fd耗尽的问题。编辑观点kqueue为macOS文件更改检测提供了一种高效的解决方案其实现相对简单但也存在一定局限性。开发者可根据具体需求选择合适的文件监控方法。