IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

监视文件系统变化——inotify

Becomin' Charles 2012-12-07 23:46:50 累计浏览 2,190 次
本机暂存

监控文件系统的变化,不是一个常见的需求,但是随着对PHP使用的深入,不可避免的会碰到这类问题。我所在的公司,在服务器端,使用PHP进程常驻内存,来完成一些任务,甚至伺服服务。我们知道,PHP作为服务器动态语言,是不需要编译的,但是代码的生命周期是仅限于一次请求的,一次请求结束,下次请求,就会重新加载代码,除非安装了Opcode Cache,但是如果PHP常驻进程,这种自动加载更新代码的能力就失去了。这时候,我们有一种弥补方案,就是使用inotify。

inotify是系统体层提供的机制,在版本号大于2.6.13的内核中才有提供(之前kernel版本,有dnotify)。PHP官方扩展库pecl提供了该扩展包。关于inotify的基本原理和用法介绍,可以看IBM的文档

inotify的API接口非常少,只有5个函数,_init,inotifiy_read,_add_watch,_rm_watch,_qeueue_len,这几个函数的含义还是相当直接的,估计比较难理解的,就只有一个init和read函数了。这里简单解释一下,inotify是一个类似队列一样的东西,把需要监控的一批文件和目录,加入到同一个inotify队列中,所以首先要先init一个空队列出来,然后用add_watch函数来添加监控对象。然后,read函数就能大显身手了,read函数可以产生一个(默认)阻塞的操作,查询监控的对象中是否有事件发生,如果有,就会返回数据,否则就一直阻塞。当然,也可以设置成非阻塞的,可以看相关代码范例。

inotify能够监控的文件系统事件罗列如下,基本上涵盖了linux server上的所有的文件事件。根据PHP官方文档和我实际测试,inotify不支持目录递归遍历,所以,如果要监控目录的变化,需要把每一个子目录都加入到watch的列表中去。除此之外,因为我在虚拟机上测试,还发现了一点,就是宿主机编辑共享文件,guest系统中的inotify无法监控到文件的变化。

IN_ACCESS           :1
IN_MODIFY           :2
IN_ATTRIB           :4
IN_CLOSE_WRITE      :8
IN_CLOSE_NOWRITE    :16
IN_OPEN             :32
IN_MOVED_TO         :128
IN_MOVED_FROM       :64
IN_CREATE           :256
IN_DELETE           :512
IN_DELETE_SELF      :1024
IN_MOVE_SELF        :2048
IN_CLOSE            :24
IN_MOVE             :192
IN_ALL_EVENTS       :4095
IN_UNMOUNT          :8192
IN_Q_OVERFLOW       :16384
IN_IGNORED          :32768
IN_ISDIR            :1073741824
IN_ONLYDIR          :16777216
IN_DONT_FOLLOW      :33554432
IN_MASK_ADD         :536870912
IN_ONESHOT          :-2147483648

最后,简单写了一个小的目录监控的类,名字叫DirWatcher,就是目录监视器的意思,主要功能,就是可以向一个监视器实例注册监控目录和回调函数,从而实现一个文件系统事件触发动作的目的。特此奉上源代码,供诸君研究相关api的使用方法,也可用于自己的系统实现中。

  1. <?php

  2. define('DIRWATCHER_CHANGED', IN_MODIFY | IN_CLOSE_WRITE | IN_MOVE| IN_CREATE | IN_DELETE);

  3. /**

  4.  * DirWatcher

  5.  *

  6.  * @author Charles Tang <charlestang AT foxmail DOT com>

  7.  */

  8. classDirWatcher{

  9.     private$_callbacks = array();

  10.     private$_directories = array();

  11.     private$_inotify = null;

  12.     publicfunction__construct(){

  13.         $this->_inotify = inotify_init();

  14.     }

  15.     publicfunctionaddDirectory($path, $mask =DIRWATCHER_CHANGED){

  16.         $key = md5($path);

  17.         if(!isset($this->_directories[$key])){

  18.             $wd = inotify_add_watch($this->_inotify, $path,$mask);

  19.             $this->_directories[$key] = array(

  20.                 'wd' => $wd,

  21.                 'path' => $path,

  22.                 'mask' => $mask,

  23.             );

  24.         }

  25.     }

  26.     publicfunctionremoveDirectory($path){

  27.         $key = md5($path);

  28.         if(isset($this->_directories[$key])){

  29.             $wd = $this->_directories[$key]['wd'];

  30.             if(inotify_rm_watch($this->_inotify, $wd)){

  31.                 unset($this->_directories[$key]);

  32.             }

  33.         }

  34.     }

  35.     publicfunctionaddDirectories($directories){

  36.         foreach($directoriesas$dir){

  37.             if(!is_array($dir)){

同分类推荐文章

  1. 等了十年的 Go 链式管道,终于来了:seq 让你像写 Scala 一样写 Go (2026-06-25 18:38:18)
  2. Go 实验特性详解 (2026-06-21 10:05:27)
  3. amd64 微架构级别对 Go 程序性能提升多少? (2026-06-21 09:38:49)

查看更多 后端 文章 →

建议继续学习

  1. 使用gettext来支持PHP的多语言 (累计阅读 39,270)
  2. WordPress插件开发 -- 在插件使用数据库存储数据 (累计阅读 29,164)
  3. Paypal接口详细代码(PHP版,非API接口) (累计阅读 19,408)
  4. 我的PHP,Python和Ruby之路 (累计阅读 13,147)
  5. include(“./file.php”)和include(“file.php”)区别 (累计阅读 12,789)
  6. 15个最好的免费开源电子商务平台 (累计阅读 12,541)
  7. Redis消息队列的若干实现方式 (累计阅读 12,088)
  8. 到底什么是MVC? (累计阅读 11,867)
  9. 整理了一份招PHP高级工程师的面试题 (累计阅读 11,708)
  10. Rolling cURL: PHP并发最佳实践 (累计阅读 11,488)