fsnotify เป็นไลบรารีการแจ้งเตือนระบบไฟล์ที่เขียนด้วย Go ซึ่งสามารถตรวจสอบการเปลี่ยนแปลงของไฟล์และไดเรคทอรีในระบบไฟล์และแจ้งให้แอปพลิเคชันทราบเมื่อเกิดการเปลี่ยนแปลง มันรองรับการทำงาน跨แพลตฟอร์มและสามารถทำงานได้บนระบบปฏิบัติการที่แตกต่างกัน เช่น Linux, macOS, และ Windows fsnotify ใช้กลไกการแจ้งเตือนระบบไฟล์ของระบบปฏิบัติการต่าง ๆ เช่น inotify บน Linux, FSEvents บน macOS, และ ReadDirectoryChangesW บน Windows

ต้องใช้ Go 1.17 หรือเวอร์ชันที่ใหม่กว่า สามารถดูเอกสารที่สมบูรณ์ได้ที่ https://pkg.go.dev/github.com/fsnotify/fsnotify

การรองรับสำหรับระบบปฏิบัติการที่แตกต่างกัน:

Backend Operating System Status
inotify Linux Supported
kqueue BSD, macOS Supported
ReadDirectoryChangesW Windows Supported
FEN illumos Supported
fanotify Linux 5.9+ ยังไม่ได้รับการรองรับ
AHAFS AIX AIX branch; Experimental feature due to lack of maintainers and test environment
FSEvents macOS ต้องการการรองรับ x/sys/unix
USN Journals Windows ต้องการการรองรับ x/sys/windows
Polling All ยังไม่ได้รับการรองรับ

Android และ Solaris ซึ่งควรรวมถึง Linux และ illumos ยังไม่ได้ทดสอบ

การใช้งาน

การใช้งานของ fsnotify รวมถึง แต่ไม่จำกัดอยู่ที่ฉากหลักต่อไปนี้:

  1. ซิงโครไนเอชนไพล์แบบเรียลไทม์: fsnotify สามารถตรวจสอบการเปลี่ยนแปลงในระบบไฟล์แบบเรียลไทม์ ทำให้เหมาะสำหรับการนำไปใช้ในการซิงค์ไฟล์แบบเรียลไทม์ เมื่อเกิดการเปลี่ยนแปลงในไฟล์ต้นฉบับ การเปลี่ยนแปลงก็สามารถซิงค์ไปยังไฟล์เป้าหมายทันที ทำให้ไฟล์เหล่านั้นมีความสอดคล้องกัน
  2. การสร้างอัตโนมัติ: fsnotify สามารถตรวจสอบการเปลี่ยนแปลงในโค้ดต้นฉบับของโปรเจกต์และไฟล์ที่ต้องการ โดยเรียกใช้คำสั่งสร้างหน่วยงานเมื่อเกิดการเปลี่ยนแปลง ซึ่งสามารถผลักดันการสร้างอัตโนมัตินี้ จะสามารถประหยัดเวลาและความพยายามของการสร้างด้วยมือและเพิ่มความสามารถในการพัฒนา
  3. การสำรองข้อมูลไฟล์: fsnotify สามารถตรวจสอบการเปลี่ยนแปลงของไฟล์หรือไดเรคทอรีที่ต้องการถูกสำรองข้อมูล และเมื่อเกิดการเปลี่ยนแปลง การสำรองข้อมูลจะถูกเริ่มต้นทันที นี้จะให้ความมั่นคงของข้อมูลและป้องกันการสูญเสียข้อมูลที่เกิดจากการสูญเสียหรือเสียหาย
  4. การตรวจสอบบันทึกเรียลไทม์: fsnotify สามารถตรวจสอบการดำเนินการเช่น การสร้าง การแก้ไข และการลบของไฟล์บันทึกเมื่อเกิดการเปลี่ยนแปลงในไฟล์บันทึก ทำให้สามารถตรวจสอบการเปลี่ยนแปลงในเนื้อหาบันทึกแบบเรียลไทม์ได้อย่างมีประสิทธิภาพ
  5. การตรวจสอบความปลอดภัยของระบบไฟล์: fsnotify สามารถตรวจสอบเหตุการณ์ทางความปลอดภัยในระบบไฟล์ เช่น การเข้าถึงไฟล์ การแก้ไข และการลบ ซึ่งทำให้สามารถตรวจสอบความปลอดภัยของระบบไฟล์ได้อย่างรวดเร็ว ตรวจพบเหตุการณ์ที่ไม่ปลอดภัยและระบุได้ทันที

ตัวอย่างการใช้งาน

ตัวอย่างพื้นฐาน:

package main

import (
    "log"

    "github.com/fsnotify/fsnotify"
)

func main() {
    // สร้าง watcher ใหม่
    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:", event)
                if event.Has(fsnotify.Write) {
                    log.Println("Modified file:", event.Name)
                }
            case err, ok := <-watcher.Errors:
                if !ok {
                    return
                }
                log.Println("Error:", err)
            }
        }
    }()

    // เพิ่มเส้นทางที่ต้องการตรวจสอบ
    err = watcher.Add("/tmp")
    if err != nil {
        log.Fatal(err)
    }

    // บล็อกโปรแกรมหลัก
    <-make(chan struct{})
}

สามารถหาตัวอย่างเพิ่มเติมได้ที่ cmd/fsnotify และสามารถรันได้โดยใช้คำสั่งต่อไปนี้:

% go run ./cmd/fsnotify

เอกสารที่ละเอียดยิ่งสามารถหาได้ใน godoc: https://pkg.go.dev/github.com/fsnotify/fsnotify

คำถามที่พบบ่อย

จะยังคงถูกตรวจสอบหากไฟล์ถูกย้ายไปยังไดเร็คทอรีอื่น?

ไม่ นอกจากว่าคุณกำลังตรวจสอบตำแหน่งที่มันถูกย้ายไปยัง

มันจะตรวจสอบโฟลเดอร์ย่อยได้ไหม?

ไม่, คุณต้องเพิ่มการตรวจสอบสำหรับแต่ละโฟลเดอร์ที่คุณต้องการตรวจสอบ (การตรวจสอบแบบเรียกกลับถูกวางแผนไว้: #18).

ฉันต้องการตรวจสอบทั้งคู่ช่องผิดพลาดและเหตุการณ์ใน goroutine พร้อมกันหรือไม่?

ใช่ คุณสามารถใช้ select เพื่ออ่านจากทั้งสองช่องใน goroutine เดียวกัน (คุณไม่จำเป็นต้องเริ่ม goroutine โดยต่างหากสำหรับแต่ละช่อง ดูตัวอย่างได้).

ทำไมการแจ้งเตือนไม่ทำงานบน NFS, SMB, FUSE, /proc, หรือ /sys?

fsnotify ต้องการการสนับสนุนจากระบบปฏิบัติการฐานเบียนเพื่อทำงาน โปรๆคอล NFS และ SMB ปัจจุบันไม่ให้การสนับสนุนระดับเครือข่ายสำหรับการแจ้งเตือนของไฟล์ และระบบไฟล์เสมือนเสมือน /proc และ /sys ก็ไม่ให้การสนับสนุน

สามารถแก้ไขได้โดยใช้การดูแลด้วยการสำรวจเฉพาะ (#9) แต่ขณะนี้ยังไม่ได้ทำการปรับปรุง

ทำไมฉันได้รับเหตุการณ์ Chmod จำนวนมาก?

บางโปรแกรมอาจสร้างการเปลี่ยนแปลงคุณสมบัติจำนวนมาก เช่น Spotlight บน macOS, โปรแกรมต้านไวรัส, โปรแกรมสำรองข้อมูล และบางโปรแกรมที่รู้จักอื่นๆ โดยทั่วไปการละเว้นเหตุการณ์ Chmod โดยทั่วไปมักเป็นภาคการดูแลด้วย เนื่องจากพวกเขามักจะไม่เกี่ยวข้อง และอาจสร้างปัญหา

การทำดัชนี Spotlight บน macOS อาจสร้างเหตุการณ์หลายครั้ง (ดูที่นี่ #15) ทางเลือกชั่วคราวคือเพิ่มโฟลเดอร์ของคุณไปยัง การตั้งค่าข้อมูลส่วนตัวของ Spotlight จนกว่าเราจะมีการปรับปรุงแบบ FSEvents อย่างเป็นธรรมชาติ (ดูที่นี่ #11).

การดูแลไฟล์ทำงานไม่ดี

โดยทั่วไปแล้วไม่แนะนำให้ดูแลไฟล์เดียว (แทนที่จะไดเร็กทอรี) เนื่องจากโปรแกรมมากมาย, โดยเฉพาะโปรแกรมแก้ไข, จะมีการอัพเดตไฟล์อะตอมิคอลี: มันจะเขียนลงไฟล์ชั่วคราวและจากนั้นย้ายมันไปยังตำแหน่งปลายทาง, ทับไฟล์เดิม (หรือแบบทดแย่งของมัน) การดูแลด้วยต้นฉบับของไฟล์ตอนนั้นจะหายไป

เป็นผลมาจากนั้น การขัดข้องของไฟฟล์ที่พลังงานหรือการล้มเหลวจะไม่สร้างผลลัพธ์ที่เต็มรูปแบบ

ดูแลไดเร็กทอรีแม่และใช้ Event.Name เพื่อกรองออกไฟล์ที่คุณไม่สนใจ มีตัวอย่างในcmd/fsnotify/file.go

หมายเหตุสำหรับแพลตฟอร์มที่ระบุ

Linux

เมื่อไฟล์ถูกลบ, เหตุการณ์ REMOVE จะไม่ถูกออกโดยที่นี่ไฟล์เดสก์ริปเตอร์ทุกตัวถูกปิดไป ณ เวลานั้น, เหตุการณ์ CHMOD จะถูกออก:

fp := os.Open("file")
os.Remove("file")        // CHMOD
fp.Close()               // REMOVE

นี่หรือเหตุการณ์ที่ส่งออกโดย inotify, เพราะฉะนั้นจะไม่ควรมีการเปลี่ยนแปลงมากมาย

ตัวแปร sysctl fs.inotify.max_user_watches ระบุจำนวนสูงสุดของการดูแลของแต่ละผู้ใช้, และ fs.inotify.max_user_instances ระบุจำนวนสูงสุดของ inotify instances ต่อผู้ใช้ ทุ Watcher ที่คุณสร้างคือ "instance" และทุ path ที่คุณเพิ่มคือ "watch"

นอกจากนั้น, คุณสามารถหาได้ใน /proc, ด้วย path /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, กรุณาอ้างอิงตามเอกสารของการกระจาย Linux ของคุณ):

fs.inotify.max_user_watches=124983
fs.inotify.max_user_instances=128

หากครบถึงขีดจำกัด ผลลัพธ์จะเป็น "No space left on device" หรือ "Too many open files"

kqueue (macOS, ซิสเตมึส์ทั้งหมด)

kqueue ต้องการเปิดไฟล์เดสก์ริปเตอร์สำหรับแต่ละไฟล์ที่สังเกตเห็น เพราะฉะนั้นหากคุณทราบไดเร็กทอรีที่มีไฟล์ห้าไฟล์, นี่คือหกไฟล์ บนแพลตฟอร์มเหล่านี้, คุณจะถึงขีดจำกัดของ "ไฟล์เปิดสูงสุด" ของระบบไวเร็คลี

คุณสามารถใช้ตัวแปร sysctl kern.maxfiles และ kern.maxfilesperproc เพื่อควบคุมจำนวนสูงสุดของการเปิดไฟล์ ทั้งหมด