适用于 PowerShell 5.1 及以上版本(Windows),FileSystemWatcher 需要 .NET Framework/Core
文件系统监控是自动化运维的重要能力——监控配置文件变更触发服务重载、监控上传目录自动处理新文件、监控日志目录异常增长告警。.NET 的 FileSystemWatcher 类提供了操作系统级的文件变更通知机制,比轮询扫描高效得多。结合 PowerShell 的事件处理能力,可以构建响应迅速的文件系统自动化工作流。
本文将讲解 FileSystemWatcher 的高级用法、事件处理模式,以及实用的自动化场景。
基础文件监控
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| $watcher = New-Object System.IO.FileSystemWatcher $watcher.Path = "C:\Config" $watcher.Filter = "*.json" $watcher.IncludeSubdirectories = $false $watcher.EnableRaisingEvents = $true
$action = { $path = $Event.SourceEventArgs.FullPath $name = $Event.SourceEventArgs.Name $changeType = $Event.SourceEventArgs.ChangeType $timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
Write-Host "[$timestamp] $changeType : $name" -ForegroundColor Yellow
switch ($changeType) { 'Changed' { Write-Host " 文件已修改:$path" -ForegroundColor Cyan } 'Created' { Write-Host " 新文件:$path" -ForegroundColor Green } 'Deleted' { Write-Host " 文件已删除:$path" -ForegroundColor Red } 'Renamed' { $oldName = $Event.SourceEventArgs.OldName Write-Host " 重命名:$oldName => $name" -ForegroundColor Yellow } } }
Register-ObjectEvent -InputObject $watcher -EventName Changed -Action $action -SourceIdentifier "FileChanged" Register-ObjectEvent -InputObject $watcher -EventName Created -Action $action -SourceIdentifier "FileCreated" Register-ObjectEvent -InputObject $watcher -EventName Deleted -Action $action -SourceIdentifier "FileDeleted" Register-ObjectEvent -InputObject $watcher -EventName Renamed -Action $action -SourceIdentifier "FileRenamed"
Write-Host "文件监控已启动:C:\Config\*.json" -ForegroundColor Green Write-Host "按 Enter 停止监控..." -ForegroundColor DarkGray Read-Host
Get-EventSubscriber | Unregister-Event $watcher.EnableRaisingEvents = $false $watcher.Dispose()
|
执行结果示例:
1 2 3 4 5
| 文件监控已启动:C:\Config\*.json [2025-06-19 08:30:15] Changed : appsettings.json 文件已修改:C:\Config\appsettings.json [2025-06-19 08:30:45] Created : new-config.json 新文件:C:\Config\new-config.json
|
配置文件变更自动重载
当应用配置文件变更时,自动触发服务重载:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| function Start-ConfigAutoReload {
param( [Parameter(Mandatory)] [string]$WatchPath,
[string]$Filter = "*.json",
[Parameter(Mandatory)] [string]$ServiceName,
[int]$DebounceSeconds = 5 )
$watcher = New-Object System.IO.FileSystemWatcher $watcher.Path = $WatchPath $watcher.Filter = $Filter $watcher.EnableRaisingEvents = $true
$lastReload = [datetime]::MinValue
$action = { $now = Get-Date if (($now - $lastReload).TotalSeconds -lt $DebounceSeconds) { return } $script:lastReload = $now
$fileName = $Event.SourceEventArgs.Name Write-Host "[$(Get-Date -Format 'HH:mm:ss')] 检测到配置变更:$fileName" -ForegroundColor Yellow
try { $content = Get-Content $Event.SourceEventArgs.FullPath -Raw | ConvertFrom-Json Write-Host " JSON 验证通过" -ForegroundColor Green } catch { Write-Host " JSON 验证失败,跳过重载:$($_.Exception.Message)" -ForegroundColor Red return }
Write-Host " 正在重启服务:$ServiceName..." -ForegroundColor Cyan Restart-Service -Name $ServiceName -Force $svc = Get-Service $ServiceName Write-Host " 服务状态:$($svc.Status)" -ForegroundColor $(if ($svc.Status -eq 'Running') { 'Green' } else { 'Red' }) }
Register-ObjectEvent -InputObject $watcher -EventName Changed -Action $action ` -SourceIdentifier "ConfigAutoReload_$ServiceName"
Write-Host "配置自动重载已启动" -ForegroundColor Green Write-Host " 监控路径:$WatchPath\$Filter" Write-Host " 目标服务:$ServiceName" }
Start-ConfigAutoReload -WatchPath "C:\MyApp\config" ` -ServiceName "MyApp" -DebounceSeconds 5
|
执行结果示例:
1 2 3 4 5 6 7
| 配置自动重载已启动 监控路径:C:\MyApp\config\*.json 目标服务:MyApp [08:30:15] 检测到配置变更:appsettings.json JSON 验证通过 正在重启服务:MyApp... 服务状态:Running
|
上传目录自动处理
监控上传目录,自动处理新到达的文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| function Start-UploadProcessor {
param( [string]$UploadPath = "C:\Uploads", [string]$ProcessedPath = "C:\Uploads\processed", [string]$ErrorPath = "C:\Uploads\errors" )
foreach ($path in @($UploadPath, $ProcessedPath, $ErrorPath)) { New-Item -Path $path -ItemType Directory -Force | Out-Null }
$watcher = New-Object System.IO.FileSystemWatcher $watcher.Path = $UploadPath $watcher.Filter = "*.csv" $watcher.EnableRaisingEvents = $true
$action = { $filePath = $Event.SourceEventArgs.FullPath $fileName = $Event.SourceEventArgs.Name
Start-Sleep -Seconds 2
try { $stream = [System.IO.File]::Open($filePath, 'Open', 'Read', 'Read') $stream.Close() } catch { Write-Host "文件仍被锁定,跳过:$fileName" -ForegroundColor DarkGray return }
Write-Host "处理文件:$fileName" -ForegroundColor Cyan
try { $data = Import-Csv $filePath $rowCount = $data.Count
foreach ($row in $data) { }
$destPath = Join-Path $ProcessedPath $fileName Move-Item $filePath $destPath -Force Write-Host " 已处理 $rowCount 行,移至:$destPath" -ForegroundColor Green
} catch { $errorPath = Join-Path $ErrorPath $fileName Move-Item $filePath $errorPath -Force Write-Host " 处理失败,移至:$errorPath" -ForegroundColor Red Write-Host " 错误:$($_.Exception.Message)" -ForegroundColor Red } }
Register-ObjectEvent -InputObject $watcher -EventName Created -Action $action ` -SourceIdentifier "UploadProcessor"
Write-Host "上传处理器已启动:$UploadPath" -ForegroundColor Green }
Start-UploadProcessor
|
执行结果示例:
1 2 3
| 上传处理器已启动:C:\Uploads 处理文件:customers-20250619.csv 已处理 150 行,移至:C:\Uploads\processed\customers-20250619.csv
|
注意事项
- 文件锁检测:新创建的文件可能仍在被写入,处理前应等待并检测文件锁
- 防抖处理:同一文件的修改可能在短时间内触发多次事件,使用时间戳去重
- 缓冲区大小:大量快速变更时,
FileSystemWatcher 的内部缓冲区可能溢出。通过 InternalBufferSize 属性增大缓冲区
- 网络驱动器:FileSystemWatcher 对网络路径(UNC 路径)的监控不太可靠,建议在文件服务器本地运行
- 资源释放:使用完毕后务必调用
Dispose() 释放 FileSystemWatcher 和取消事件订阅
- 事件队列:PowerShell 的事件队列可能积压,定期使用
Get-Event 处理或设置队列大小限制