监控目录下的文件操作与实时同步

若有个需求:要求记录下某个目录下的所有操作,包括创建文件、修改文件、重命名、删除文件的操作,将以上所有的操作全部记录到日志中,或者做其他操作。.NET提供了一个方法叫做“System.IO.FileSystemWatcher”,方便powershell来调用。具体使用方法,我慢慢解释。


 一、监控某个目录下的所有操作

方案一:

$folder = "c:	est"  #定义要监控哪个目录
$timeout = 1000  #设置监控的时间间隔
$filesystemwatcher = new-object System.IO.FileSystemWatcher $folder  #使用FileSystemWatcher方法开启文件监控
echo "ctrl+c will exit" while ($true) { $result = $filesystemwatcher.WaitForChanged("all",$timeout)  #监控种类,all代表监控所有操作,$timeout表示监控的时间间隔 if($result.TimedOut -eq $false)    #$result.TimedOut返回true或false,若目录下不操作返回true,
{ $time = date -UFormat "%Y-%m-%d %H-%M-%S" $type = $result.ChangeType $name = $result.Name $oldname = $result.OldName echo "$time $type $name $oldname " #显示如下信息,时间、 操作的类型、操作文件的名称、操作文件原来的名称,只有重命名后才会显示 } }

  测试:

  在c: est目录下增删改查一些文件

  终端返回的结果: 

  在所执行的终端执行ctrl+c或者关闭终端即可终止监控程序。

方案二:

  该方案与方案一不同的一点是,方案二会在后台运行,但方案一由while循环运行。

$watcher = New-Object System.IO.FileSystemWatcher  #启动监控实例
$watcher.Path = "c:	est"  #监控的路径
$watcher.IncludeSubdirectories = $true     #是否监控子目录下的文件操作
$watcher.EnableRaisingEvents = $true      #默认是true

#重写changed、created、deleted、renamed方法 $changed = Register-ObjectEvent $watcher "Changed" -Action {   $time = date -UFormat "%Y-%m-%d %H-%M-%S" write-host " $time Changed: $($eventArgs.FullPath)" } $created = Register-ObjectEvent $watcher "Created" -Action { $time = date -UFormat "%Y-%m-%d %H-%M-%S" write-host "$time Created: $($eventArgs.FullPath)" } $deleted = Register-ObjectEvent $watcher "Deleted" -Action { $time = date -UFormat "%Y-%m-%d %H-%M-%S" write-host "$time Deleted: $($eventArgs.FullPath)" } $renamed = Register-ObjectEvent $watcher "Renamed" -Action { $time = date -UFormat "%Y-%m-%d %H-%M-%S" write-host "$time Renamed: $($eventArgs.FullPath)" }

  测试:

  在被监控的目录下增删改查操作

返回的结果:

但是方案二退出与方案一的不一致。

  1、退出当前执行的终端,可以退出整个监控程序

  2、手动注销事件,注销以上重新的方法,需要在程序运行的终端执行

Unregister-Event $changed.Id
Unregister-Event $created.Id
Unregister-Event $deleted.Id
Unregister-Event $renamed.Id

  红框内的内容是输入进去的。

二、实时同步

  有了目录监控的能力,可以扩展一下,实现文件实时同步。

  有两个目录,目录A中凡是有了任何操作,便同步到B目录中,实现实时同步。具体代码如下:

【注意】

  代码中监听操作的时间隔是1000ms,若两相邻操的时间间隔作小于1000ms时,就会出现不同步的问题

$folder = "\share-server	"  #监听的源目录
$timeout = 1000  #时间间隔,ms
$filesystemwatcher = new-object System.IO.FileSystemWatcher $folder
$filesystemwatcher.IncludeSubdirectories = $true  #开启监听子目录的功能
$des = "c:	est"  #同步的目标目录
$logpath = "c:	estlogsa.log"  #日志记录的位置,需要提前创建好日志的父目录

echo "ctrl+c will exit"
cp -Force -Recurse $folder* $des  #先将源目录中的所有文件拷贝到子目录中

while ($true)  #开启监听
{
    $result = $filesystemwatcher.WaitForChanged("all",$timeout)
    if($result.TimedOut -eq $false)
    {
        $time = date -UFormat "%Y-%m-%d %H:%M:%S"  
        $type = $result.ChangeType
        $name = $result.Name
        $oldname = $result.OldName
        echo "$time  $type      $name    oldname:$oldname "  >> $logpath  #输出日志
           
        $isfile = $true
        $filefullpath = $folder + "" + $name  #源文件的全路径
        $dstpath = $des + "" + $name      #目标文件的全路劲

        if( Test-Path $filefullpath ){ $filepath = $filefullpath }  #当删除时,源文件的全路径不存在,需要借助目标文件的全路径来判断是文件还是目录
        if( Test-Path $dstpath ){ $filepath = $dstpath }

        if ( (ls $filepath) -is [IO.fileinfo])   #判断是文件还是目录
        {
           $isfile = $true  
        }
        else
        {
           $isfile = $false
        }

    #根据不同的操作类型做出不同的操作
        if( $type -eq "Changed" ) 
        {   
          if( $isfile )
          {
            cp $filefullpath $dstpath
            echo "cp $filefullpath $dstpath"  >> $logpath
          }
        }

        if( $type -eq "Created" ) 
        {
          if( $isfile )
          {
            New-Item $dstpath
            echo "cp $filefullpath $des"  >> $logpath
          }
          else
          {
            mkdir $dstpath
            echo "mkdir $dstpath"  >> $logpath
          }
        }

        if( $type -eq "Deleted" ) 
        {
          rm -Recurse -Force $dstpath
          echo "rm $dstpath"  >> $logpath
        }

        if( $type -eq "Renamed" ) 
        {
          cd $des
          mv $oldname $name
          echo "mv $oldname $name"  >> $logpath
        }
    }
}

  测试:

  日志结果:

【注意】

  以上代码存在一个缺陷,当文件在不同的目录下移动时,会有异常,只有修改一下代码逻辑便可实现。

原文地址:https://www.cnblogs.com/zqj-blog/p/10305453.html