fsnotifyはGoで書かれたファイルシステムの通知ライブラリで、ファイルシステム内のファイルやディレクトリの変更を監視し、変更が発生した際にアプリケーションに通知することができます。また、Linux、macOS、Windowsなど様々なオペレーティングシステムでクロスプラットフォームで動作し、それぞれのオペレーティングシステムのファイルシステム通知メカニズム(Linuxのinotify、macOSのFSEvents、WindowsのReadDirectoryChangesWなど)を利用しています。
Go 1.17以降が必要であり、完全なドキュメントは以下で確認できます:https://pkg.go.dev/github.com/fsnotify/fsnotify
異なるオペレーティングシステムへのサポート:
バックエンド | オペレーティングシステム | ステータス |
---|---|---|
inotify | Linux | サポート済み |
kqueue | BSD、macOS | サポート済み |
ReadDirectoryChangesW | Windows | サポート済み |
FEN | illumos | サポート済み |
fanotify | Linux 5.9+ | サポートされていません |
AHAFS | AIX | AIX分岐; 管理者とテスト環境の不足により実験的 |
FSEvents | macOS | x/sys/unixのサポートが必要 |
USN Journals | Windows | x/sys/windowsのサポートが必要 |
Polling | すべてのオペレーティングシステム | サポートされていません |
AndroidとSolarisについては、まだテストされていません。
使用例
fsnotifyの使用例は以下の通りです(但し、これに限定されません):
- リアルタイムファイル同期: fsnotifyはファイルシステムの変更をリアルタイムで監視し、リアルタイムファイル同期を実装するのに適しています。ソースファイルに変更があった際、変更内容を即座にターゲットファイルに同期することで、ファイルの一貫性を確保します。
- 自動ビルド: fsnotifyはプロジェクトのソースコードや依存ファイルの変更を監視し、変更があった際にビルドコマンドをトリガーとすることで、自動ビルドを実珅することができます。これにより手動ビルドの時間と手間を節約し、開発効率を向上させることができます。
- ファイルバックアップ: fsnotifyはバックアップが必要なファイルやディレクトリの変更を監視し、変更があった際に即座にバックアップを開始することができます。これによりデータの安全性が確保され、ファイルの紛失や損傷によるデータ損失を防ぐことができます。
- リアルタイムログ監視: fsnotifyはログファイルの作成、修正、削除といった操作を監視し、ログファイルに変更があった際にログ監視プログラムをトリガーすることで、ログ内容の変更を実時間で監視することができます。
- ファイルシステムセキュリティ監視: fsnotifyはファイルシステムでのファイルアクセス、修正、削除などのセキュリティイベントを監視できます。これによりファイルシステムのセキュリティモニタリングが可能となり、即座に不正なイベントを特定・記録することができます。
使用例
基本的な例:
package main
import (
"log"
"github.com/fsnotify/fsnotify"
)
func main() {
// 新しい監視者を作成する。
watcher, err := fsnotify.NewWatcher()
if err != nil {
log.Fatal(err)
}
defer watcher.Close()
// イベントをリッスンする。
go func() {
for {
select {
case event, ok := <-watcher.Events:
if !ok {
return
}
log.Println("イベント:", event)
if event.Has(fsnotify.Write) {
log.Println("変更されたファイル:", event.Name)
}
case err, ok := <-watcher.Errors:
if !ok {
return
}
log.Println("エラー:", err)
}
}
}()
// 監視するパスを追加する。
err = watcher.Add("/tmp")
if err != nil {
log.Fatal(err)
}
// メインゴルーチンをブロックする。
<-make(chan struct{})
}
より詳細なドキュメントはgodocから確認できます: https://pkg.go.dev/github.com/fsnotify/fsnotify
よくある質問
ファイルが別のディレクトリに移動された場合も監視されますか?
いいえ、移動先の場所が監視対象でない限り、監視されません。
サブディレクトリは監視されていますか?
いいえ、監視したいディレクトリごとに監視を追加する必要があります(再帰的な監視は計画されています:#18)。
エラーチャンネルとイベントチャンネルの両方をゴルーチンで同時に監視する必要がありますか?
はい。select
を使用して、同じゴルーチンで両方のチャンネルから読み取ることができます(各チャンネルごとに個別のゴルーチンを開始する必要はありません。例を参照してください)。
NFS、SMB、FUSE、/proc、または/sysで通知が機能しないのはなぜですか?
fsnotifyは基礎となるオペレーティングシステムからのサポートが必要です。現在のNFSとSMBプロトコルはファイルの通知のためのネットワークレベルのサポートを提供しておらず、/procと/sysの仮想ファイルシステムもサポートしていません。
これはポーリング監視プログラムを使用することで修正できます(#9)、ただし、まだ実装されていません。
なぜ多くのChmodイベントを受信していますか?
一部のプログラムは、macOSのSpotlight、ウイルス対策プログラム、バックアップアプリケーション、その他一部の既知のアプリケーションなどが属性の変更を大量に生成する場合があります。一般的には、Chmodイベントを無視するのが最良の方法です。それらはしばしば役に立たず、問題を引き起こすことがあります。
macOSのSpotlightインデックス作成により複数のイベントが発生することがあります(#15を参照)。ネイティブなFSEventsの実装があるまでの一時的な解決策として、フォルダを Spotlightのプライバシー設定 に追加することがあります(#11を参照)。
ファイルの監視がうまく機能しない
通常、個々のファイルを監視することはお勧めしません(ディレクトリではなく)ため、多くのプログラム、特にエディタは、ファイルをアトミックに更新します。それは一時ファイルに書き込み、それをターゲットの場所に移動し、元のファイルを上書きします(またはその変形)。元のファイルの監視は失われた状態になります。
その結果、停電やクラッシュは、書きかけのファイルを残すことがありません。
親ディレクトリを監視し、Event.Name
を使用して興味のないファイルをフィルタリングしてください。cmd/fsnotify/file.go
に例があります。
特定のプラットフォームの注意事項
Linux
ファイルが削除された場合、REMOVEイベントはすべてのファイルディスクリプタが閉じられるまで発行されず、その時点でCHMODイベントが発行されます:
fp := os.Open("file")
os.Remove("file") // CHMOD
fp.Close() // REMOVE
これはinotifyが送信するイベントであり、それにあまり変更を加えることはありません。
fs.inotify.max_user_watches
シスカル変数は、ユーザーごとの最大監視数を指定し、fs.inotify.max_user_instances
はユーザーごとのinotifyインスタンスの最大数を指定します。作成する各Watcherは「インスタンス」であり、追加する各パスは「監視」となります。
これらは/proc
にも見つけることができ、パスは /proc/sys/fs/inotify/max_user_watches
と /proc/sys/fs/inotify/max_user_instances
です。
これらを増やすには、sysctl
を使用するか、値をprocファイルに書き込むことができます:
sysctl fs.inotify.max_user_watches=124983
sysctl fs.inotify.max_user_instances=128
変更を再起動後に有効にするには、/etc/sysctl.conf
または /usr/lib/sysctl.d/50-default.conf
を編集してください(詳細は各Linuxディストリビューションごとに異なる場合がありますので、ディストリビューションのドキュメントを参照してください):
fs.inotify.max_user_watches=124983
fs.inotify.max_user_instances=128
限界値に達すると、「デバイスの空き容量がありません」 または「開いているファイルが多すぎます」というエラーが発生します。
kqueue(macOS、すべてのBSDシステム)
kqueueは、観察されているファイルごとにファイルディスクリプタを開く必要があります。したがって、5つのファイルを含むディレクトリを観察している場合、6つのファイルディスクリプタが必要です。これらのプラットフォームでは、システムの "最大オープンファイル" 限界により、より早く制限に達します。
システムの最大オープンファイル数を制御するために、kern.maxfiles
および kern.maxfilesperproc
のsysctl変数を使用することができます。