本文目录导读:

- Python - watchdog 库(跨平台推荐)
- Linux - inotify(原生高效)
- Node.js - chokidar
- Bash - 简单轮询检测
- Windows - PowerShell
- Go - fsnotify
- macOS - fsevents(Swift)
- 性能对比
- 最佳实践建议
有多种方法可以检测文件变动,具体取决于你的使用场景和操作系统,以下是主流方案:
Python - watchdog 库(跨平台推荐)
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
class ChangeHandler(FileSystemEventHandler):
def on_modified(self, event):
if not event.is_directory:
print(f"文件被修改: {event.src_path}")
def on_created(self, event):
print(f"文件被创建: {event.src_path}")
def on_deleted(self, event):
print(f"文件被删除: {event.src_path}")
# 监控当前目录
observer = Observer()
observer.schedule(ChangeHandler(), '.', recursive=True)
observer.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()
Linux - inotify(原生高效)
# 安装 inotify-tools sudo apt-get install inotify-tools # Debian/Ubuntu # 监控文件变化 inotifywait -m -r -e modify,create,delete /path/to/watch
Shell 脚本示例:
#!/bin/bash
inotifywait -m -e modify,create,delete /path/to/watch | while read event
do
echo "检测到变化: $event"
# 执行你的操作
done
Node.js - chokidar
const chokidar = require('chokidar');
const watcher = chokidar.watch('/path/to/watch', {
persistent: true,
ignoreInitial: true
});
watcher
.on('add', path => console.log(`文件 ${path} 被创建`))
.on('change', path => console.log(`文件 ${path} 被修改`))
.on('unlink', path => console.log(`文件 ${path} 被删除`));
Bash - 简单轮询检测
#!/bin/bash
file="/path/to/file.txt"
last_md5=$(md5sum "$file" | awk '{print $1}')
while true; do
current_md5=$(md5sum "$file" | awk '{print $1}')
if [ "$last_md5" != "$current_md5" ]; then
echo "文件发生变化"
last_md5=$current_md5
# 执行操作
fi
sleep 1
done
Windows - PowerShell
# 使用 FileSystemWatcher
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = "C:\path\to\watch"
$watcher.Filter = "*.*"
$watcher.EnableRaisingEvents = $true
Register-ObjectEvent $watcher "Changed" -Action {
Write-Host "文件 $($Event.SourceEventArgs.FullPath) 被修改"
}
# 保持脚本运行
while ($true) { Start-Sleep -Seconds 1 }
Go - fsnotify
package main
import (
"log"
"github.com/fsnotify/fsnotify"
)
func main() {
watcher, _ := fsnotify.NewWatcher()
defer watcher.Close()
watcher.Add("/path/to/watch")
for {
select {
case event := <-watcher.Events:
log.Println("事件:", event)
case err := <-watcher.Errors:
log.Println("错误:", err)
}
}
}
macOS - fsevents(Swift)
import Foundation
let stream = FSEventStreamCreate(
kCFAllocatorDefault,
{ _, _, _, eventPaths, _, _ in
for path in eventPaths {
print("文件变化: \(path)")
}
},
nil,
["/path/to/watch"] as CFArray,
FSEventStreamEventId(kFSEventStreamEventIdSinceNow),
0.5,
FSEventStreamCreateFlags(kFSEventStreamCreateFlagFileEvents)
)
性能对比
| 方法 | 平台 | 效率 | 延迟 | 准确性 |
|---|---|---|---|---|
| inotify | Linux | 即时 | 高 | |
| fsevents | macOS | 即时 | 高 | |
| ReadDirectoryChangesW | Windows | 即时 | 高 | |
| watchdog | 跨平台 | 即时 | 高 | |
| 轮询(MD5) | 所有 | 有延迟 | 中 | |
| 时间戳检查 | 所有 | 有延迟 | 中 |
最佳实践建议
- 生产环境:使用操作系统原生API(inotify/fsevents/ReadDirectoryChanges)
- 跨平台需求:使用 watchdog (Python) 或 chokidar (Node.js)
- 简单脚本:使用 inotifywait (Linux) 或 md5sum 轮询
- 避免频繁读取:对大型文件使用变化通知而非轮询
- 处理批量事件:设置去抖(debounce)逻辑
选择哪种方案取决于你的操作系统、编程语言偏好和性能要求。