首页 > 代码库 > Window Linux下实现指定目录内文件变更的监控方法

Window Linux下实现指定目录内文件变更的监控方法

转自:http://qbaok.blog.163.com/blog/static/10129265201112302014782/

对于监控指定目录内文件变更,window 系统提供了两个未公开API:SHChangeNotifyRegister  SHChangeNotifyDeregister 分别用于注册Notify以及监视。

同时,还提供了ReadDirectoryChangesW  函数(貌似NT以上可用)。

在 .net framework 中,另提供了封装好的 FileSystemWatcher 来实现此功能。

至于 JAVA PHP 神马的,太晚了,懒得查了,以后再说。

============ 【分割线】=============

ReadDirectoryChangesW 函数具体信息如下:

对指定的目录进行监控,返回详细的文件变化信息。

函数形式

01 BOOL WINAPI ReadDirectoryChangesW(

02 __in         HANDLE hDirectory,   // 对目录进行监视的句柄

03 __out        LPVOID lpBuffer,     // 一个指向DWORD类型的缓冲区,其中可以将获取的数据结果将其返回。

04 __in         DWORD nBufferLength, // 指lpBuffer的缓冲区的大小值,以字节为单位。

05 __in         BOOL bWatchSubtree, // 监视目录. 一般选择 TRUE

06 __in         DWORD dwNotifyFilter, // 对文件过滤的方式和标准

07 __out_opt    LPDWORD lpBytesReturned, // 将接收的字节数转入lpBuffer参数

08 __inout_opt LPOVERLAPPED lpOverlapped, // 一般选择 NULL

09 __in_opt     LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine // 一般选择 NULL

10 );

1.hDirectory [中]

       This directory must be opened with the FILE_LIST_DIRECTORY access right.

       被监视的目录必须打开FILE_LIST_DIRECTORY的访问权限

2.lpBuffer[中]

       The structure of this buffer is defined by the FILE_NOTIFY_INFORMATION structure

       这个缓冲区的定义是FILE_NOTIFY_INFORMATION结构。

       This buffer is filled either synchronously or asynchronously,

       depending on how the directory is opened and what value is given to the lpOverlapped parameter.

       这个缓冲区充满要么同步或异步,这取决于如何打开目录什么价值给予lpOverlapped参数。

3.nBufferLength [中]

       The size of the buffer that is pointed to by the lpBuffer parameter, in bytes.

       大小的缓冲区,是指出的lpBuffer参数,以字节为单位。

4.bWatchSubtree [中]

       If this parameter is TRUE, the function monitors the directory tree rooted at the specified directory.

       如果这个参数是TRUE,那么这个函数会监视目录树,所指定的当前的根目录(整个路径信息都显示出来)。

       If this parameter is FALSE, the function monitors only the directory specified by the hDirectory parameter.

       如果这个参数是FALSE ,则函数则只监视hDirectory句柄所指定的目录下的内容(只显示出发生变化的文件目录)。

5.dwNotifyFilter [中]

       The filter criteria that the function checks to determine if the wait operation has completed.

       该过滤器的标准,功能检查,以决定是否等待操作完成。

       This parameter can be one or more of the following values.这个参数可以是一个或多个下列值。

      【FILE_NOTIFY_CHANGE_FILE_NAME】 0x00000001

       Any file name change in the watched directory or subtree causes a change notification wait operation to return.

       任何文件名改变 都会查看所在目录或子目录的变更,并将结果通知给等待操作返回。

       Changes include renaming, creating, or deleting a file.

       变化包括重命名,创建或删除文件。

      【FILE_NOTIFY_CHANGE_DIR_NAME】 0x00000002

       Any directory-name change in the watched directory or subtree causes a change notification wait operation to return.

       任何目录名称改变 都会查看所在目录或子目录的变更,并将结果通知给等待操作返回。

       Changes include creating or deleting a directory.

       改变包括建立或删除一个目录。

      【FILE_NOTIFY_CHANGE_ATTRIBUTES】 0x00000004

       Any attribute change in the watched directory or subtree causes a change notification wait operation to return.

       任何属性变化,都会查看所在目录或子目录的变更,并将结果通知给等待操作返回。

      【FILE_NOTIFY_CHANGE_SIZE】 0x00000008

       Any file-size change in the watched directory or subtree causes a change notification wait operation to return.

       任何文件大小的变化,都会查看所在目录或子目录的变更,并将结果通知给等待操作返回。

       The operating system detects a change in file size only when the file is written to the disk.

       操作系统检测改变文件大小,只有当该文件被写入到磁盘时发生。

       For operating systems that use extensive caching, detection occurs only when the cache is sufficiently flushed.

       操作系统使用广泛缓存,检测时才会发生的缓存足够同满。

      【FILE_NOTIFY_CHANGE_LAST_WRITE】0x00000010

       Any change to the last write-time of files in the watched directory or subtree causes a change notification wait operation to return.

       任何改变过去修改时间的文件 ,都会查看所在目录或子目录的变更,并将结果通知给等待操作返回。

       The operating system detects a change to the last write-time only when the file is written to the disk.

       操作系统检测改变过去写的时间只有当该文件被写入到磁盘。

       For operating systems that use extensive caching, detection occurs only when the cache is sufficiently flushed.

       操作系统使用广泛缓存,检测时才会发生的缓存足够同满。

      【FILE_NOTIFY_CHANGE_LAST_ACCESS】0x00000020

       Any change to the last access time of files in the watched directory or subtree causes a change notification wait operation to return.

       任何改变文件最近访问时间,都会查看所在目录或子目录的变更,并将结果通知给等待操作返回。

      【FILE_NOTIFY_CHANGE_CREATION】 0x00000040

       Any change to the creation time of files in the watched directory or subtree causes a change notification wait operation to return.

       任何改变文件的创建时间的,都会查看所在目录或子目录的变更,并将结果通知给等待操作返回。

      【FILE_NOTIFY_CHANGE_SECURITY】0x00000100

       Any security-descriptor change in the watched directory or subtree causes a change notification wait operation to return.

       任何安全描述符被改变的,都会查看所在目录或子目录的变更,并将结果通知给等待操作返回。

6.lpBytesReturned [了,可选]

       For synchronous calls, this parameter receives the number of bytes transferred into the lpBuffer parameter.

       同步调用,这个参数接收的字节数转入lpBuffer参数。

       For asynchronous calls, this parameter is undefined.

       异步调用,这个参数是未定义的。

       You must use an asynchronous notification technique to retrieve the number of bytes transferred.

       您必须使用异步通知技术检索的字节数转移。

7.lpOverlapped [中,那样,可选]

       A pointer to an OVERLAPPED structure that supplies data to be used during asynchronous operation.

       一个指针的重叠结构,提供供数据时使用的异步操作。

       Otherwise, this value is NULL.

       否则,这个值为NULL 。

       The Offset and OffsetHigh members of this structure are not used.

       OFFSET和OffsetHigh成员结构不使用。

8.lpCompletionRoutine [中,可选]

       A pointer to a completion routine to be called when the operation has been completed or canceled and the calling

       thread is in an alertable wait state.

       一个指针一个完成例程 如果在呼叫使用函数操作时已经完成或取消和调用线程是在alertable等待状态。

返回值

       If the function succeeds, the return value is nonzero.

       如果函数成功,返回值为非零。

       For synchronous calls, this means that the operation succeeded.

       同步要求,这意味着操作取得了成功。

       For asynchronous calls, this indicates that the operation was successfully queued.

       异步调用,这表明操作成功排队。

If the function fails, the return value is zero.

如果函数失败,返回值是零。

To get extended error information, call GetLastError .

要获得扩展错误信息,请用GetLastError返回错误 。

If the network redirector or the target file system does not support this operation, the function fails with ERROR_INVALID_FUNCTION.

如果网络重定向或目标文件系统不支持这一行动,该功能失败, ERROR_INVALID_FUNCTION 。

========= 抄来的 delphi FileSystemWatcher 实现 ==========

{*******************************************************}

{                                                       }

{       FileSystemWatcher                               }

{                                                       }

{       版权所有 (C) 2007 solokey                       }

{                                                       }

{       http://blog.csdn.net/solokey                    }

{                                                       }

{*******************************************************}

unit FileSystemWatcher;

interface

uses

  Windows, Classes, SysUtils;

type

  TFileOperation = (foAdded, foRemoved, foModified, foRenamed);

  TFileDealMethod = procedure(FileOperation: TFileOperation; const FileName1,FileName2: string) of object;

  TNotifyFilter = (nfFileNameChange, nfDirNameChange, nfAttributeChange,

    nfSizeChange, nfWriteChange, nfAccessChange, nfCreationDateChange, nfSecurityChange);

  TNotifyFilters = set of TNotifyFilter;

  TNotificationBuffer =  array[0..4095] of Byte;

  PFileNotifyInformation = ^TFileNotifyInformation;

  TFileNotifyInformation = record

    NextEntryOffset: DWORD;

    Action: DWORD;

    FileNameLength: DWORD;

    FileName: array[0..0] of WideChar;

  end;

  TShellChangeThread = class(TThread)

  private

    FActived: Boolean;

    FDirectoryHandle: Cardinal;

    FCS: TRTLCriticalSection;

    FChangeEvent: TFileDealMethod;

    FDirectory: string;

    FWatchSubTree: Boolean;

    FCompletionPort: Cardinal;

    FOverlapped: TOverlapped;

    FNotifyOptionFlags: DWORD;

    FBytesWritten: DWORD;

    FNotificationBuffer: TNotificationBuffer;

  protected

    procedure Execute; override;

    procedure DoIOCompletionEvent;

    function ResetReadDirctory: Boolean;

    procedure Lock;

    procedure Unlock;

  public

    constructor Create(ChangeEvent: TFileDealMethod); virtual;

    destructor Destroy; override;

    procedure SetDirectoryOptions(Directory : String; Actived: Boolean; WatchSubTree : Boolean;

      NotifyOptionFlags : DWORD);

    property ChangeEvent : TFileDealMethod read FChangeEvent write FChangeEvent;

  end;

  TFileSystemWatcher = class(TComponent)

  private

    FActived: Boolean;

    FWatchedDir: string;

    FThread: TShellChangeThread;

    FOnChange: TFileDealMethod;

    FWatchSubTree: Boolean;

    FFilters: TNotifyFilters;

    procedure SetWatchedDir(const Value: string);

    procedure SetWatchSubTree(const Value: Boolean);

    procedure SetOnChange(const Value: TFileDealMethod);

    procedure SetFilters(const Value: TNotifyFilters);

    function  NotifyOptionFlags: DWORD;

    procedure SetActived(const Value: Boolean);

  protected

    procedure Change;

    procedure Start;

    procedure Stop;

  public

    constructor Create(AOwner : TComponent); override;

    destructor  Destroy; override;

  published

    property  Actived:Boolean  read FActived write SetActived;

    property  WatchedDir: string read FWatchedDir write SetWatchedDir;

    property  WatchSubTree: Boolean read FWatchSubTree write SetWatchSubTree;

    property  NotifyFilters: TNotifyFilters read FFilters write SetFilters;

    property  OnChange: TFileDealMethod read FOnChange write SetOnChange;

  end;

procedure  Register;

implementation

procedure  Register;

begin

  RegisterComponents(‘Samples‘, [TFileSystemWatcher]);

end;

{ TShellChangeThread }

constructor TShellChangeThread.Create(ChangeEvent: TFileDealMethod);

begin

  FreeOnTerminate := True;

  FChangeEvent := ChangeEvent;

  InitializeCriticalSection(FCS);

  FDirectoryHandle := 0;

  FCompletionPort := 0;

  inherited Create(True);

end;

destructor TShellChangeThread.Destroy;

begin

  CloseHandle(FDirectoryHandle);

  CloseHandle(FCompletionPort);

  DeleteCriticalSection(FCS);

  inherited Destroy;

end;

procedure TShellChangeThread.DoIOCompletionEvent;

var

  TempBuffer: TNotificationBuffer;

  FileOpNotification: PFileNotifyInformation;

  Offset: Longint;

  FileName1, FileName2: string;

  FileOperation: TFileOperation;

  procedure DoDirChangeEvent;

  begin

    if Assigned(ChangeEvent) and FActived then

      ChangeEvent(FileOperation, FileName1, FileName2);

  end;

  function  CompleteFileName(const FileName:string):string;

  begin

    Result := ‘‘;

    if Trim(FileName) <> ‘‘ then

      Result := FDirectory + Trim(FileName);

  end;

begin

  Lock;

  TempBuffer := FNotificationBuffer;

  FillChar(FNotificationBuffer, SizeOf(FNotificationBuffer), 0);

  Unlock;

  Pointer(FileOpNotification) := @TempBuffer[0];

  repeat

    with FileOpNotification^ do begin

      Offset := NextEntryOffset;

      FileName2 := ‘‘;

      case Action of

        FILE_ACTION_ADDED..FILE_ACTION_MODIFIED: begin

          FileName1 := CompleteFileName(WideCharToString(FileName));

          FileOperation := TFileOperation(Action - 1);

          DoDirChangeEvent;

        end;

        FILE_ACTION_RENAMED_OLD_NAME: begin

          FileName1 := CompleteFileName(WideCharToString(FileName));

          FileOperation := TFileOperation(Action - 1);

        end;

        FILE_ACTION_RENAMED_NEW_NAME: begin

          if FileOperation = foRenamed then begin

            FileName2 := CompleteFileName(WideCharToString(FileName));

            DoDirChangeEvent;

          end;

        end;

      end;

    end;

  Pointer(FileOpNotification) := Pointer(PChar(FileOpNotification) + OffSet);

  until Offset=0;

end;

procedure TShellChangeThread.Execute;

var

  numBytes: DWORD;

  CompletionKey: DWORD;

  PFOverlapped: POverlapped;

  TempDirectoryHandle: Cardinal;

  TempCompletionPort: Cardinal;

begin

  while not Terminated do begin

    Lock;

    TempDirectoryHandle := FDirectoryHandle;

    TempCompletionPort := FCompletionPort;

    Unlock;

    if TempDirectoryHandle > 0  then begin

      PFOverlapped := @FOverlapped;

      GetQueuedCompletionStatus(TempCompletionPort, numBytes, CompletionKey, PFOverlapped, INFINITE);

      if CompletionKey = Handle then begin

        Synchronize(DoIOCompletionEvent);

        FBytesWritten := 0;

        FillChar(FNotificationBuffer, SizeOf(FNotificationBuffer), 0);

        ReadDirectoryChanges(FDirectoryHandle, @FNotificationBuffer, SizeOf(FNotificationBuffer), FWatchSubTree, FNotifyOptionFlags, @FBytesWritten, @FOverlapped, nil);

      end;

    end;

  end;

  PostQueuedCompletionStatus(TempCompletionPort, 0, 0, nil);

end;

procedure TShellChangeThread.Lock;

begin

  EnterCriticalSection(FCS);

end;

function TShellChangeThread.ResetReadDirctory: Boolean;

var

  TempHandle: Cardinal;

  TempCompletionPort: Cardinal;

begin

  Result := False;

  CloseHandle(FDirectoryHandle);

  PostQueuedCompletionStatus(FCompletionPort, 0, 0, nil);

  CloseHandle(FCompletionPort);

  TempHandle := CreateFile(PChar(FDirectory), GENERIC_READ or GENERIC_WRITE,

                            FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE,

                            nil, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS or FILE_FLAG_OVERLAPPED, 0);

  Lock;

  FDirectoryHandle := TempHandle;

  Unlock;

  if (GetLastError = ERROR_FILE_NOT_FOUND) or (GetLastError = ERROR_PATH_NOT_FOUND) then begin

    Lock;

    FDirectoryHandle := 0;

    FCompletionPort := 0;

    Unlock;

    Exit;

  end;

  TempCompletionPort := CreateIoCompletionPort(FDirectoryHandle, 0, Handle, 0);

  Lock;

  FCompletionPort := TempCompletionPort;

  Unlock;

  FBytesWritten := 0;

  FillChar(FNotificationBuffer, SizeOf(FNotificationBuffer), 0);

  Result := ReadDirectoryChanges(FDirectoryHandle, @FNotificationBuffer, SizeOf(FNotificationBuffer), FWatchSubTree, FNotifyOptionFlags, @FBytesWritten, @FOverlapped, nil);

end;

procedure TShellChangeThread.SetDirectoryOptions(Directory: String; Actived: Boolean;

  WatchSubTree: Boolean;  NotifyOptionFlags : DWORD);

begin

  FWatchSubTree := WatchSubTree;

  FNotifyOptionFlags := NotifyOptionFlags;

  FDirectory := IncludeTrailingBackslash(Directory);

  FActived := Actived;

  ResetReadDirctory;

end;

procedure TShellChangeThread.Unlock;

begin

  LeaveCriticalSection(FCS);

end;

{ TFileSystemWatcher }

procedure TFileSystemWatcher.Change;

begin

  if csDesigning in ComponentState then

    Exit;

  if Assigned(FThread) then begin

    FThread.SetDirectoryOptions(FWatchedDir, FActived, LongBool(FWatchSubTree), NotifyOptionFlags);

  end;

end;

constructor TFileSystemWatcher.Create(AOwner: TComponent);

begin

  inherited Create(AOwner);

  FActived := False;

  FWatchedDir := ‘C:\‘;

  FFilters := [nfFilenameChange, nfDirNameChange];

  FWatchSubTree := True;

  FOnChange := nil;

end;

destructor TFileSystemWatcher.Destroy;

begin

  if Assigned(FThread) then

    FThread.Terminate;

  inherited Destroy;

end;

function TFileSystemWatcher.NotifyOptionFlags: DWORD;

begin

  Result := 0;

  if nfFileNameChange in FFilters then

    Result := Result or FILE_NOTIFY_CHANGE_FILE_NAME;

  if nfDirNameChange in FFilters then

    Result := Result or FILE_NOTIFY_CHANGE_DIR_NAME;

  if nfSizeChange in FFilters then

    Result := Result or FILE_NOTIFY_CHANGE_SIZE;

  if nfAttributeChange in FFilters then

    Result := Result or FILE_NOTIFY_CHANGE_ATTRIBUTES;

  if nfWriteChange in FFilters then

    Result := Result or FILE_NOTIFY_CHANGE_LAST_WRITE;

  if nfAccessChange in FFilters then

    Result := Result or FILE_NOTIFY_CHANGE_LAST_ACCESS;

  if nfCreationDateChange in FFilters then

    Result := Result or FILE_NOTIFY_CHANGE_CREATION;

  if nfSecurityChange in FFilters then

    Result := Result or FILE_NOTIFY_CHANGE_SECURITY;

end;

procedure TFileSystemWatcher.SetActived(const Value: Boolean);

begin

  if FActived <> Value then begin

    FActived := Value;

    Change;

    if FActived then

      Start

    else

      Stop;

  end;

end;

procedure TFileSystemWatcher.SetFilters(const Value: TNotifyFilters);

begin

  if FFilters <> Value then begin

    FFilters := Value;

    Change;

  end;

end;

procedure TFileSystemWatcher.SetOnChange(const Value: TFileDealMethod);

begin

  FOnChange := Value;

  if Assigned(FOnChange) and FActived then

    Start

  else

    Stop;

  Change;

end;

procedure TFileSystemWatcher.SetWatchedDir(const Value: string);

begin

  if not SameText(FWatchedDir, Value) then begin

    FWatchedDir := Value;

    Change;

  end;

end;

procedure TFileSystemWatcher.SetWatchSubTree(const Value: Boolean);

begin

  if FWatchSubTree <> Value then begin

    FWatchSubTree := Value;

    Change;

  end;

end;

procedure TFileSystemWatcher.Start;

begin

  if csDesigning in ComponentState then

    Exit;

  if Assigned(FOnChange) then begin

    FThread := TShellChangeThread.Create(FOnChange);

    FThread.SetDirectoryOptions(FWatchedDir, FActived, LongBool(FWatchSubTree), NotifyOptionFlags);

    FThread.Resume;

  end;

end;

procedure TFileSystemWatcher.Stop;

begin

  if csDesigning in ComponentState then

    Exit;

  if Assigned(FThread) then begin

    FThread.Terminate;

    FThread := nil;

  end;

end;

end.

============ 【分割线】=============

至于 Linux 么…… PW 哥给找的 Linux inotify 还是很给力的。

见 http://snipt.org/wngpo

  1. #!/bin/bash

  2. SRC=http://www.mamicode.com/home/pw/workspace/daobo/web_demo/

  3. DST=username@remote_host:/home/pw/workspace/resin-3.0.21/webapps/daobo-demo

  4. inotifywait -mrq -e modify --exclude=".*\.swp|\.svn|.*\~" $SRC |while read D E F;do

  5. rsync -avz $SRC $DST --exclude=".svn" --exclude=".*\.swp"

  6. done

至于这鸟玩意是个啥,怎么装,资料如下:

inotify 是什么

Inotify一种强大的、细粒度的、异步文件系统监控机制,它满足各种各样的文件监控需要,可以监控文件系统的访问属性、读写属性、权限属性、删除创建 移动等操作,也就是可以监控文件发生的一切变化,我们可以利用内核提供的这个属性,在文件发生任何变化时都触发rsync同步动作,这样就做到数据的实时 同步了。

Inotify的监控功能是需要内核支持的,Linux从kernel 2.6.13开始,Inotify功能正式加入内核,在RHEL5版本已经完全支持。

为什么使用 inotify?

使用 inotify 取代 dnotify 的原因有很多。第一个原因是,dnotify 需要您为每个打算监控是否发生改变的目录打开一个文件描述符。当同时监控多个目录时,这会消耗大量的资源, 因为有可能达到每个进程的文件描述符限制。

除此之外,文件描述符会锁定目录,不允许卸载(unmount)支持的设备,这在存在可移动介质的 环境中会引发问题。在使用 inotify 时,如果正在监控被卸载的文件系统上的文件,那么监控会被自动移除并且您会接收到一个卸载事件。

dnotify 不如 inotify 的第二个原因是 dnotify 有点复杂。注意,使用 dnotify 基础设施的简单文件系统监控粒度只 停留于目录级别。为了使用 dnotify 进行更细粒度的监控,应用程序编程 人员必须为每个受监控的目录保留一个 stat 结构的缓存。该用户空间的 stat 结构缓存需要用来明确确定当接收到通知信号时目录发生了什么变化。当获得通知信号时,生成 stat 结构列表并与最新的状态相比较。显而易见,这种技术是不理想的。

inotify 的另一个优点是它使用文件描述符作为基本接口,使应用程序开发者使用 select 和 poll 来监控设备。这允许有效的多路 I/O 和与 Glib 的 mainloop 的集成。相反,dnotify 所使用的信号常常使程序员头疼并且感觉不太优雅。

inotify 通过提供一个更优雅的 API 解决了这些问题,该 API 使用最少的文件描述符,并确保更细粒度的监控。与 inotify 的通信是通过设备节点提供的。基 于以上原因,对于监控 Linux 2.6 平台上的文件,inotify 是您最明智的选择。

另外,要在shell下使用inotify提供的特性,还需要安装 inotify-tools,我们依次介绍如下:

安装inotify-tools

可以在  http://inotify-tools.sourceforge.net/ 下载到inotify-tools,接着编译安装:

[root@web253 ~]# tar zxvf inotify-tools-3.13.tar.gz

[root@web253 ~]# cd inotify-tools-3.13

[root@web253 inotify-tools-3.13]# ./configure

[root@web253 inotify-tools-3.13]#make

[root@web253 inotify-tools-3.13]#make install

完成后,在系统下执行man inotify 、 man inotifywait、man inotifywatch即可得到相应的帮助信息。表示安装成功。

使用inotify功能

可以通过如下命令查看系统是否支持inotify

[root@web253 bin]# uname -a

Linux web253 2.6.18-8.el5 #1 SMP Fri Jan 26 14:15:21 EST 2007 i686 i686 i386 GNU/Linux

[root@web253 bin]# ll /proc/sys/fs/inotify

total 0

-rw-r--r-- 1 root root 0 Feb 21 01:15 max_queued_events

-rw-r--r-- 1 root root 0 Feb 21 01:15 max_user_instances

-rw-r--r-- 1 root root 0 Feb 21 01:15 max_user_watches

如果有输出,表示系统已经内核已经支持inotify。

inotify 可以监视的文件系统事件包括:

IN_ACCESS, 即文件被访问

IN_MODIFY, 文件被 write

IN_ATTRIB, 文件属性被修改,如 chmod、chown、touch 等

IN_CLOSE_WRITE, 可写文件被 close

IN_CLOSE_NOWRITE, 不可写文件被 close

IN_OPEN, 文件被 open

IN_MOVED_FROM, 文件被移走,如 mv

IN_MOVED_TO, 文件被移来,如 mv、cp

IN_CREATE, 创建新文件

IN_DELETE, 文件被删除,如 rm

IN_DELETE_SELF, 自删除,即一个可执行文件在执行时删除自己

IN_MOVE_SELF,自移动,即一个可执行文件在执行时移动自己

IN_UNMOUNT,宿主文件系统被 umount

IN_CLOSE,文件被关闭,等同于(IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)

IN_MOVE,文件被移动,等同于(IN_MOVED_FROM | IN_MOVED_TO)

注:上面所说的文件也包括 目录。

inotifywait 仅执行阻塞,等待 inotify 事件。您可以监控任何一组文件和目录,或监控整个目录树(目录、 子目录、子目录的子目录等等)。在 shell 脚本中使用 inotifywait。

inotifywatch 收集关于被监视的文件系统的统计数据,包括每个 inotify 事件发生多少次。

inotify的系统相关参数

/proc interfaces

       The following interfaces can be used to limit the amount of kernel memory consumed by inotify:

/proc/sys/fs/inotify/max_queued_events

       The value in this file is used when an application calls inotify_init(2) to set an upper  limit  on  the number  of  events  that  can be queued to the corresponding inotify instance.  Events in excess of this limit are dropped, but an IN_Q_OVERFLOW event is always generated.

/proc/sys/fs/inotify/max_user_instances

        This specifies an upper limit on the number of inotify instances that can be created per real user ID.

/proc/sys/fs/inotify/max_user_watches

        This specifies a limit on the number of watches that can be associated with each inotify instance.

inotifywait 相关的命令(更多,查看manpage):

inotifywait

This command simply blocks for inotify events, making it appropriate for use in shell scripts. It can watch any set of files and directories, and can recursively watch entire directory trees.

-m, --monitor

              Instead  of  exiting  after receiving a single event, execute indefinitely.  The default behaviour is to exit after the first event occurs.

-r, --recursive

              Watch all subdirectories of any directories passed as arguments.  Watches will be set up recursively  to an  unlimited  depth.   Symbolic  links  are  not traversed.  Newly created subdirectories will also be watched.

-q, --quiet

              If specified once, the program will be less verbose.  Specifically, it will not state when it  has  completed establishing all inotify watches.

-e <event>, --event <event>

              Listen for specific event(s) only.  The events which can be listened for are listed in the  EVENTS  section.  This option can be specified more than once.  If omitted, all events are listened for. use“,”separate multi events。

Window Linux下实现指定目录内文件变更的监控方法