Java WatchService在查看映射驱动器时不生成事件

时间:2011-12-12 15:11:14

标签: java file nio mapped-drive watchservice

我实现了一个文件监视器,但我注意到java nio文件监视器不会为映射驱动器上复制的文件生成事件。例如,我在Unix上运行文件观察器来观察映射在windows(/sharedfolder)上的本地目录(H:\),然后我将一个文件放在这个目录中({ {1}})但是文件观察者没有生成任何事件。现在,如果我在Windows上运行文件观察器来观察映射驱动器(H:\),它引用了unix路径(H:\),并且从unix我将文件放在此文件夹中,文件监视器会识别改变并生成一个事件。它看起来像一个bug,或者可能是我遗漏了一些东西,有什么想法吗?

5 个答案:

答案 0 :(得分:25)

我在尝试通过CIFS观看已安装的Windows共享时遇到同样的问题。 似乎无法获得filesystem events for CIFS mounts

Java 7 NIO FileWatcher的linux实现使用 inotify 。 Inotify是一个Linux内核子系统,用于注意文件系统更改,这些更改适用于本地目录,但显然不适用于CIFS mounts

在Oracle,修复this bug似乎不是高优先级。 (这是他们的责任吗?更多的操作系统问题......)

JNotify也在linux系统上使用 inotify ,所以这也没有选择。

因此,映射驱动器监控似乎仅限于轮询器:

  • Apache VFS DefaultFileMonitor轮询目录(已安装的共享)
  • 基于标准Java API的文件轮询器。
  • 自定义文件轮询器jCIFS(因此不需要在主机上安装共享)

我可能会尝试Apache VFS Monitor,因为它可以检测文件创建,更新和删除。它需要挂载共享,但这使操作系统负责CIFS连接,而不是我的应用程序。

答案 1 :(得分:4)

JDK中的文件监视功能取决于平台,因为它使用本机库,因此它可能在不同平台上表现不同。我很惊讶它完全适用于网络驱动器 - Windows必须轮询网络映射驱动器以进行更改,而Linux则不然(理所当然,我应该说)。

通常在OS内核中实现这种监控,这显然知道哪些文件在本地被修改/创建/等等,但是没有简单的方法让操作系统知道网络驱动器上发生了什么,因为它没有独占控制权。它

答案 2 :(得分:2)

我遇到了同样的问题。我已经通过在de main类中创建一个新线程并定期触摸文件来解决它,因此会触发一个新的更改事件。

样本每隔10秒轮询dir一次。

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

    }

}

答案 3 :(得分:1)

我遇到类似的问题,Python脚本在远程Windows目录中查看日志文件的内容。

这是我的答案。

/etc/fstab使用//xxx.xxx.xxx.xxx/shareddrive /media/shareddrive cifs username=xxxx,password=xxxx,**directio** 0 0

时,从Unix映射远程驱动器

您可以使用凭证文件来避免以明文形式提供密码。

该命令可能会根据unix版本而改变,这是在debian下测试的。 它应该按预期工作。 你能告诉我它是否有效吗? 我计划在Java中实现相同的东西,所以答案也可能对我有用。

答案 4 :(得分:1)

我也碰到了这个并且和其他人一样得到了同样的结论(CIFS + inotify = no go)。

然而,由于我的工作流程依赖于依赖于inotify的远程挂载和自动编译工具,我最终构建了一个(相当绝望和苛刻的)解决方案,它基本上只使用轮询来监视更改然后触摸在安装的一侧再次使用相同的文件, 似乎触发了inotify事件。这不是我最自豪的时刻。

话虽如此,它确实有效,所以,享受:http://github.com/rubyruy/watchntouch