監控目錄下的文件操作與實時同步


若有個需求:要求記錄下某個目錄下的所有操作,包括創建文件、修改文件、重命名、刪除文件的操作,將以上所有的操作全部記錄到日志中,或者做其他操作。.NET提供了一個方法叫做“System.IO.FileSystemWatcher”,方便powershell來調用。具體使用方法,我慢慢解釋。


 一、監控某個目錄下的所有操作

方案一:

$folder = "c:\test"  #定義要監控哪個目錄
$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:\test目錄下增刪改查一些文件

  終端返回的結果: 

  在所執行的終端執行ctrl+c或者關閉終端即可終止監控程序。

 

方案二:

  該方案與方案一不同的一點是,方案二會在后台運行,但方案一由while循環運行。

$watcher = New-Object System.IO.FileSystemWatcher  #啟動監控實例
$watcher.Path = "c:\test\"  #監控的路徑
$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\t"  #監聽的源目錄
$timeout = 1000  #時間間隔,ms
$filesystemwatcher = new-object System.IO.FileSystemWatcher $folder
$filesystemwatcher.IncludeSubdirectories = $true  #開啟監聽子目錄的功能
$des = "c:\test"  #同步的目標目錄
$logpath = "c:\test\logs\a.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
        }
    }
}

  測試:

  日志結果:

【注意】

  以上代碼存在一個缺陷,當文件在不同的目錄下移動時,會有異常,只有修改一下代碼邏輯便可實現。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM