fsnotify es una biblioteca de notificación del sistema de archivos escrita en Go, que puede monitorear cambios en archivos y directorios en el sistema de archivos y notificar a la aplicación cuando ocurren cambios. Admite operaciones multiplataforma y puede ejecutarse en diferentes sistemas operativos como Linux, macOS y Windows. fsnotify utiliza los mecanismos de notificación del sistema de archivos de diferentes sistemas operativos, como inotify en Linux, FSEvents en macOS y ReadDirectoryChangesW en Windows.
Requiere el uso de Go 1.17 o versiones posteriores; la documentación completa se puede encontrar en https://pkg.go.dev/github.com/fsnotify/fsnotify
Soporte para diferentes sistemas operativos:
Backend | Sistema Operativo | Estado |
---|---|---|
inotify | Linux | Soportado |
kqueue | BSD, macOS | Soportado |
ReadDirectoryChangesW | Windows | Soportado |
FEN | illumos | Soportado |
fanotify | Linux 5.9+ | Aún no soportado |
AHAFS | AIX | Rama para AIX; Función experimental debido a la falta de mantenimiento y entorno de prueba |
FSEvents | macOS | Requiere soporte x/sys/unix |
Diarios USN | Windows | Requiere soporte x/sys/windows |
Sondeo | Todos | Aún no soportado |
Android y Solaris, que deberían incluir Linux e illumos, aún no han sido probados.
Casos de uso
Los casos de uso de fsnotify incluyen, pero no se limitan a, las siguientes situaciones:
- Sincronización de archivos en tiempo real: fsnotify puede monitorear cambios en el sistema de archivos en tiempo real, lo que lo hace adecuado para implementar la sincronización de archivos en tiempo real. Cuando ocurren cambios en el archivo de origen, los cambios se pueden sincronizar inmediatamente en el archivo de destino, garantizando la consistencia de los archivos.
- Compilación automatizada: fsnotify puede monitorear cambios en el código fuente del proyecto y archivos de dependencias, desencadenando comandos de compilación cuando ocurren cambios, logrando así una compilación automatizada. Esto puede ahorrar tiempo y esfuerzo de la compilación manual y mejorar la eficiencia del desarrollo.
- Copia de seguridad de archivos: fsnotify puede monitorear cambios en archivos o directorios que necesitan ser respaldados e iniciar una copia de seguridad inmediata cuando ocurren cambios. Esto garantiza la seguridad de los datos y evita la pérdida de datos debido a la pérdida o daño del archivo.
- Monitoreo de registros en tiempo real: fsnotify puede monitorear operaciones como la creación, modificación y eliminación de archivos de registro, desencadenando programas de monitoreo de registros cuando ocurren cambios en los archivos de registro, lo que permite monitorear efectivamente los cambios en el contenido del registro en tiempo real.
- Monitoreo de seguridad del sistema de archivos: fsnotify puede monitorear eventos de seguridad en el sistema de archivos, como acceso, modificación y eliminación de archivos. Esto permite el monitoreo de seguridad del sistema de archivos, identificando y registrando rápidamente eventos inseguros.
Ejemplo de uso
Un ejemplo básico:
paquete principal
import (
"registro"
"github.com/fsnotify/fsnotify"
)
func main() {
// Crear un nuevo observador.
observador, err := fsnotify.NewWatcher()
if err != nil {
log.Fatal(err)
}
defer observador.Close()
// Empezar a escuchar eventos.
go func() {
para {
seleccionar {
caso evento, ok := <-observador.Events:
if !ok {
regresar
}
log.Println("Evento:", evento)
if evento.Has(fsnotify.Write) {
log.Println("Archivo modificado:", evento.Name)
}
caso err, ok := <-observador.Errors:
if !ok {
regresar
}
log.Println("Error:", err)
}
}
}()
// Agregar la ruta que necesita ser monitoreada.
err = observador.Add("/tmp")
if err != nil {
log.Fatal(err)
}
// Bloquear la goroutine principal.
<-make(chan struct{})
}
Se pueden encontrar más ejemplos en cmd/fsnotify y se pueden ejecutar usando el siguiente comando:
% go run ./cmd/fsnotify
Se puede encontrar documentación más detallada en godoc: https://pkg.go.dev/github.com/fsnotify/fsnotify
Preguntas Frecuentes
¿Seguirá siendo monitoreado si el archivo es movido a otro directorio?
No, a menos que esté monitoreando la ubicación a la que se mueve.
¿Se monitorizan los subdirectorios?
No, debe agregar monitoreo para cada directorio que desee vigilar (se planea monitoreo recursivo: #18).
¿Necesito monitorear simultáneamente los canales de error y evento en un goroutine?
Sí. Puede usar select
para leer de ambos canales en el mismo goroutine (no es necesario iniciar un goroutine por separado para cada canal; ver el ejemplo).
¿Por qué las notificaciones no funcionan en NFS, SMB, FUSE, /proc o /sys?
fsnotify requiere soporte del sistema operativo subyacente para funcionar. Los protocolos actuales de NFS y SMB no proporcionan soporte a nivel de red para notificaciones de archivos, y los sistemas de archivos virtuales /proc y /sys tampoco lo proporcionan.
Esto podría solucionarse utilizando un observador de sondeo (#9), pero aún no se ha implementado.
¿Por qué recibo muchos eventos Chmod?
Algunos programas pueden generar una gran cantidad de cambios de atributos, como Spotlight en macOS, programas antivirus, aplicaciones de respaldo y algunas otras aplicaciones conocidas. En general, ignorar los eventos Chmod suele ser la mejor práctica, ya que a menudo son inútiles y pueden causar problemas.
La indexación de Spotlight en macOS puede causar múltiples eventos (ver #15). Una solución temporal es agregar sus carpetas a Configuración de privacidad de Spotlight hasta que tengamos una implementación nativa de FSEvents (ver #11).
La vigilancia de archivos no funciona bien
Generalmente, no se recomienda vigilar archivos individuales (en lugar de directorios) porque muchos programas, especialmente editores, actualizarán atómicamente los archivos: escribirán en un archivo temporal y luego lo moverán a la ubicación de destino, sobrescribiendo el archivo original (o alguna variante de él). El monitor en el archivo original ahora se ha perdido porque el archivo ya no existe.
Como resultado, un fallo de energía o un bloqueo no dará como resultado un archivo medio escrito.
Vigile el directorio principal y use Event.Name
para filtrar los archivos que no le interesan. Hay un ejemplo en cmd/fsnotify/file.go
.
Notas para Plataformas Específicas
Linux
Cuando se elimina un archivo, el evento REMOVE no se emitirá hasta que se cierren todos los descriptores de archivo; en este momento, se emitirá un evento CHMOD:
fp := os.Open("file")
os.Remove("file") // CHMOD
fp.Close() // REMOVE
Este es el evento enviado por inotify, por lo que no debería haber demasiados cambios en él.
La variable sysctl fs.inotify.max_user_watches
especifica el número máximo de observaciones por usuario, y fs.inotify.max_user_instances
especifica el número máximo de instancias de inotify por usuario. Cada Watcher que cree es una "instancia" y cada ruta que agregue es una "observación".
Estos también se pueden encontrar en /proc
, con las rutas /proc/sys/fs/inotify/max_user_watches
y /proc/sys/fs/inotify/max_user_instances
.
Para aumentarlos, puede usar sysctl
o escribir los valores en el archivo proc:
sysctl fs.inotify.max_user_watches=124983
sysctl fs.inotify.max_user_instances=128
Para que los cambios surtan efecto después de un reinicio, edite /etc/sysctl.conf
o /usr/lib/sysctl.d/50-default.conf
(los detalles pueden variar para cada distribución de Linux, consulte la documentación de su distribución):
fs.inotify.max_user_watches=124983
fs.inotify.max_user_instances=128
Alcanzar el límite resultará en errores "No queda espacio en el dispositivo" o "Demasiados archivos abiertos".
kqueue (macOS, todos los sistemas BSD)
kqueue requiere abrir un descriptor de archivo para cada archivo observado; por lo tanto, si está observando un directorio que contiene cinco archivos, son seis descriptores de archivo. En estas plataformas, alcanzará más rápidamente el límite de "máximo de archivos abiertos" del sistema.
Puede usar las variables sysctl kern.maxfiles
y kern.maxfilesperproc
para controlar el número máximo de archivos abiertos.