
Go: Building and Using a Simple File Watcher
To implement a file watcher, we will utilize the fsnotify package, which provides a cross-platform way to watch for file system events. This tutorial will guide you through the installation of the package, setting up a basic file watcher, and handling different types of file events.
Prerequisites
- Go installed on your machine (version 1.11 or higher).
- Basic understanding of Go programming language.
Installation
First, create a new directory for your Go project and navigate into it:
mkdir file-watcher
cd file-watcherNext, initialize a new Go module:
go mod init file-watcherNow, install the fsnotify package:
go get github.com/fsnotify/fsnotifyCreating the File Watcher
Create a new file named main.go in your project directory:
package main
import (
"fmt"
"log"
"github.com/fsnotify/fsnotify"
)
func main() {
// Create a new file watcher
watcher, err := fsnotify.NewWatcher()
if err != nil {
log.Fatal(err)
}
defer watcher.Close()
// Start a goroutine to listen for events
go func() {
for {
select {
case event, ok := <-watcher.Events:
if !ok {
return
}
// Handle file events
if event.Op&fsnotify.Write == fsnotify.Write {
fmt.Println("Modified file:", event.Name)
}
if event.Op&fsnotify.Create == fsnotify.Create {
fmt.Println("Created file:", event.Name)
}
if event.Op&fsnotify.Remove == fsnotify.Remove {
fmt.Println("Deleted file:", event.Name)
}
if event.Op&fsnotify.Rename == fsnotify.Rename {
fmt.Println("Renamed file:", event.Name)
}
case err, ok := <-watcher.Errors:
if !ok {
return
}
log.Println("Error:", err)
}
}
}()
// Add a directory to watch
err = watcher.Add("./watched_directory")
if err != nil {
log.Fatal(err)
}
// Block forever
<-make(chan struct{})
}Explanation of the Code
- Imports: We import necessary packages, including
fsnotifyfor file watching andlogfor error handling. - Creating a Watcher: We create a new file watcher instance using
fsnotify.NewWatcher(). - Goroutine for Event Listening: A goroutine listens for file system events and handles them appropriately. We check the type of event (write, create, remove, rename) and print a message to the console.
- Adding a Directory to Watch: We specify the directory we want to monitor. Make sure to create a directory named
watched_directoryin your project folder. - Blocking the Main Goroutine: We use a channel to block the main goroutine indefinitely, allowing the watcher to continue running.
Running the File Watcher
To run the file watcher, execute the following command in your terminal:
go run main.goNow, create a directory named watched_directory in your project folder:
mkdir watched_directoryYou can now test the file watcher by creating, modifying, or deleting files within the watched_directory. For example, create a new file:
touch watched_directory/test.txtYou should see an output like:
Created file: watched_directory/test.txtHandling File Events
The current implementation simply prints messages to the console. However, you can extend this functionality to perform more complex actions, such as:
- Reloading configuration files.
- Triggering builds or deployments.
- Sending notifications.
To demonstrate this, let's modify the file watcher to execute a command when a file is created. You can use the os/exec package to run shell commands.
Add the following import statement at the beginning of your main.go:
import (
"os/exec"
)Then, modify the if event.Op&fsnotify.Create == fsnotify.Create section in the event handling goroutine:
if event.Op&fsnotify.Create == fsnotify.Create {
fmt.Println("Created file:", event.Name)
// Execute a command (for example, a shell command)
cmd := exec.Command("echo", "A file was created!")
err := cmd.Run()
if err != nil {
log.Println("Error executing command:", err)
}
}Now, when you create a file in the watched directory, the program will execute the echo command.
Conclusion
In this tutorial, we've built a simple file watcher in Go using the fsnotify package. We covered how to monitor a directory for file system events and respond to those events with appropriate actions. This file watcher can be further enhanced to suit more complex use cases.
