Java WatchService no genera eventos mientras mira unidades mapeadas
file nio (5)
Implementé un vigilante de archivos pero noté que el vigilante de archivos java nio no genera eventos para los archivos que se copian en las unidades mapeadas. Por ejemplo, he ejecutado el vigilante de archivos en Unix para ver un directorio local ( /sharedfolder
) que está mapeado en Windows ( H:/
), y luego he puesto un archivo en este directorio ( H:/
) pero el File Watcher no ha generado ningún evento. Ahora si ejecuto el vigilante de archivos en Windows para observar la unidad mapeada ( H:/
) que se refiere a una ruta de acceso unix ( /sharedfolder
) y de unix pongo un archivo en esta carpeta, el observador de archivos identifica el cambio y genera un evento . Parece un error, o puede ser que me falta algo, ¿algún pensamiento?
La funcionalidad de visualización de archivos en JDK depende de la plataforma, ya que utiliza bibliotecas nativas para que se comporte de manera diferente en diferentes plataformas. Me sorprende que funcione para las unidades de red: Windows debe ser una red de sondeo de las unidades mapeadas por cambios mientras que Linux no (por lo que debería decir).
Por lo general, este tipo de monitoreo se implementa en el núcleo del sistema operativo, que obviamente tiene conocimiento de qué archivos se modifican / crean / etc localmente, pero no hay formas fáciles para que el sistema operativo sepa qué sucede en la unidad de red, ya que no tiene control exclusivo sobre ella.
Tuve problemas similares con un script de Python que miraba el contenido de un archivo de registro en un directorio remoto de Windows.
Aquí está mi respuesta.
Al mapear la unidad remota desde Unix, en /etc/fstab
utilice //xxx.xxx.xxx.xxx/shareddrive /media/shareddrive cifs username=xxxx,password=xxxx,**directio** 0 0
Puede usar un archivo de credenciales para evitar tener la contraseña en texto sin formato.
El comando podría cambiar dependiendo de la versión de Unix, esto se probó en debian. Debería funcionar como estaba previsto. ¿Me puede decir si funciona? Planeo implementar lo mismo en Java, por lo que la respuesta también podría ser útil para mí.
Yo también encontré esto y llegué a la misma conclusión que todos los demás aquí (CIFS + inotify = no go).
Sin embargo, como mi flujo de trabajo dependía tanto de los montajes remotos como de las herramientas de compilación automática que dependen de inotify, terminé construyendo una solución (bastante desesperada y hacky) que básicamente usa encuestas para ver los cambios y luego vuelve a tocar los mismos archivos en el lado montado, que parece despedir eventos inotify. No es mi momento de mayor orgullo.
Habiendo dicho eso, funciona, así que, disfruta: http://github.com/rubyruy/watchntouch
Yo tuve el mismo problema. Lo he resuelto creando un nuevo hilo en la clase principal y tocando los archivos periódicamente para que se active un nuevo evento de cambio.
La muestra sondea el directorio por cada 10 segundos.
package com.ardevco.files;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.FileTime;
import java.util.ArrayList;
import java.util.List;
public class Touch implements Runnable {
private Path touchPath;
public Touch(Path touchPath) {
this.touchPath = touchPath;
this.checkPath = checkPath;
}
public static void touch(Path file) throws IOException {
long timestamp = System.currentTimeMillis();
touch(file, timestamp);
}
public static void touch(Path file, long timestamp) throws IOException {
if (Files.exists(file)) {
FileTime ft = FileTime.fromMillis(timestamp);
Files.setLastModifiedTime(file, ft);
}
}
List<Path> listFiles(Path path) throws IOException {
final List<Path> files = new ArrayList<>();
try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) {
for (Path entry : stream) {
if (Files.isDirectory(entry)) {
files.addAll(listFiles(entry));
}
files.add(entry);
}
}
return files;
}
@Override
public void run() {
while (true) {
try {
for (Path path : listFiles(touchPath)) {
touch(path);
}
} catch (IOException e) {
System.out.println("Exception: " + e);
}
try {
Thread.sleep(10000L);
} catch (InterruptedException e) {
System.out.println("Exception: " + e);
}
}
}
}
Tengo el mismo problema al tratar de ver un compartimiento de Windows montado a través de CIFS. Parece que no es posible obtener eventos del sistema de archivos para montajes CIFS .
La implementación de Linux de Java 7 NIO FileWatcher utiliza inotify . Inotify es un subsistema de kernel de Linux para observar los cambios en el sistema de archivos que funciona perfecto para directorios locales, pero aparentemente no para montajes CIFS .
En Oracle, no parece ser de alta prioridad solucionar este error . (¿Es su responsabilidad? Más un problema de sistema operativo ...)
JNotify también usa inotify en sistemas Linux, por lo que tampoco es una opción.
Por lo tanto, el seguimiento de las unidades mapeadas parece estar limitado a los sondeadores:
- Apache VFS DefaultFileMonitor para sondear directorios (compartido compartido)
- File Poller basado en la API Java estándar.
- Custom File Poller con jCIFS (por lo que no es necesario que el recurso compartido esté montado en el host)
Probablemente probaré Apache VFS Monitor, porque detecta la creación de archivos, las actualizaciones y las elimina de la caja. Requiere montar el recurso compartido, pero eso le da al sistema operativo la responsabilidad de las conexiones CIFS y no de mi aplicación.