31

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

4

5 回答 5

30

我在尝试通过 CIFS 观看已安装的 Windows 共享时遇到同样的问题。似乎无法获取CIFS 挂载的文件系统事件

Java 7 NIO FileWatcher 的 linux 实现使用inotify。Inotify 是一个 linux 内核子系统,用于通知文件系统更改,非常适合本地目录,但显然不适用于CIFS 挂载

在甲骨文,修复这个错误似乎不是很重要的事情。(这是他们的责任吗?更多的是操作系统问题......)

JNotify也在 linux 系统上使用inotify,所以这也不是选项。

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

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

于 2012-09-19T12:18:28.937 回答
4

JDK 中的文件监视功能依赖于平台,因为它使用本机库,因此它在不同平台上的行为可能不同。我很惊讶它完全适用于网络驱动器 - Windows 必须轮询网络映射驱动器以进行更改,而 Linux 没有(我应该说是正确的)。

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

于 2011-12-12T15:33:00.053 回答
3

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

该示例每 10 秒轮询一次目录。

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

    }

}
于 2015-05-01T10:24:35.933 回答
1

我也遇到了这个问题,并得出了与这里的其他人相同的结论(CIFS + inotify = 不行)。

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

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

于 2013-05-05T03:51:16.403 回答
1

我在使用 Python 脚本监视远程 Windows 目录上的日志文件内容时遇到了类似的问题。

这是我的答案。

从 Unix 映射远程驱动器时,在/etc/fstab使用//xxx.xxx.xxx.xxx/shareddrive /media/shareddrive cifs username=xxxx,password=xxxx,**directio** 0 0

您可以使用凭证文件来避免使用纯文本密码。

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

于 2012-09-19T10:29:08.103 回答