Java WatchService not generating events while watching mapped drives

允我心安 提交于 2019-11-27 08:02:15
Tim Van Laer

I have the same issue trying to watch a mounted windows share via CIFS. It seems not possible to get filesystem events for CIFS mounts.

The linux implementation of the Java 7 NIO FileWatcher uses inotify. Inotify is a linux kernel subsystem to notice filesystem changes which works perfect for local directories, but apparently not for CIFS mounts.

At Oracle, it doesn't seem to be high priority to fix this bug. (Is it their responsibility? More of an OS issue...)

JNotify also uses inotify on linux systems, so this is no option either.

So mapped drives monitoring unfortunately seems to be limited to pollers:

  • Apache VFS DefaultFileMonitor to poll directories (mounted share)
  • File Poller based on the standard Java API.
  • Custom File Poller with jCIFS (so the share doesn't need to be mounted on the host)

I'll probably try the Apache VFS Monitor, because it detects file creation, updates and deletes out of the box. It requires to mount the share, but that gives the OS the responsibility of CIFS connections and not my application.

File watching functionality in JDK is platform dependent as it uses native libraries so it could behave differently on different platform. I'm surprised it works for network drives at all - Windows must be polling network mapped drives for changes while Linux doesn't (rightfully so I should say).

Usually this sort of monitoring implemented in OS kernel, which obviously has knowledge which files are modified/created/etc locally but there are no easy ways for OS to know what happening on network drive as it doesn't have exclusive control over it.

I had the same problem. I have solved it by creating a new thread in de main class and touching the files periodically so a new change event gets fired.

The sample polls the dir for every 10 seconds does a touch.

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);
            }
        }

    }

}
1337Wolf

I had similar issues with a Python script watching content of a log file on a remote windows directory.

Here is my answer.

When mapping the remote drive from the Unix, in the /etc/fstab use //xxx.xxx.xxx.xxx/shareddrive /media/shareddrive cifs username=xxxx,password=xxxx,**directio** 0 0

You can use a credentials file to avoid having the password in plain text.

The command could change depending on the unix version, this was tested under debian. It should work as intended. Can you tell me if it works ? I plan on Implementing the same stuff in Java so the answer might be useful to me as well.

I too ran into this and reached the same conclusion as everyone else here (CIFS + inotify = no go).

However, since my workflow happened to depend on both remote mounts and auto-compile tools that rely on inotify, I ended up building a (fairly desperate & hacky) solution which basically just uses polling to watch for changes and then touches the same files again on the mounted side, which does seem to fire off inotify events. It is not my proudest moment.

Having said that, it does work, so, enjoy: http://github.com/rubyruy/watchntouch

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!