我实现了一个文件观察器,但我注意到 java nio 文件观察器不会为在映射驱动器上复制的文件生成事件。例如,我在 Unix 上运行文件观察器来观察/sharedfolder
映射到 windows () 上的本地目录 () H:\
,然后我在这个目录 ( H:\
) 中放置了一个文件,但文件观察器没有生成任何事件. 现在,如果我在 Windows 上运行文件观察器来观察映射驱动器 ( H:\
),它指的是一个 unix 路径 ( /sharedfolder
),并且从 unix 我将一个文件放在这个文件夹中,文件观察器会识别更改并生成一个事件。它看起来像一个错误,或者我可能遗漏了一些东西,有什么想法吗?
5 回答
我在尝试通过 CIFS 观看已安装的 Windows 共享时遇到同样的问题。似乎无法获取CIFS 挂载的文件系统事件。
Java 7 NIO FileWatcher 的 linux 实现使用inotify。Inotify 是一个 linux 内核子系统,用于通知文件系统更改,非常适合本地目录,但显然不适用于CIFS 挂载。
在甲骨文,修复这个错误似乎不是很重要的事情。(这是他们的责任吗?更多的是操作系统问题......)
JNotify也在 linux 系统上使用inotify,所以这也不是选项。
因此,不幸的是,映射驱动器监控似乎仅限于轮询器:
- Apache VFS DefaultFileMonitor轮询目录(挂载共享)
- 基于标准 Java API 的文件轮询器。
- 带有jCIFS的自定义文件轮询器(因此共享不需要安装在主机上)
我可能会尝试 Apache VFS Monitor,因为它开箱即用地检测文件创建、更新和删除。它需要挂载共享,但这让操作系统负责 CIFS 连接,而不是我的应用程序。
JDK 中的文件监视功能依赖于平台,因为它使用本机库,因此它在不同平台上的行为可能不同。我很惊讶它完全适用于网络驱动器 - Windows 必须轮询网络映射驱动器以进行更改,而 Linux 没有(我应该说是正确的)。
通常这种监控是在操作系统内核中实现的,它显然知道哪些文件在本地被修改/创建/等,但是操作系统没有简单的方法来知道网络驱动器上发生的事情,因为它没有对它的排他控制权。
我有同样的问题。我已经通过在 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);
}
}
}
}
我也遇到了这个问题,并得出了与这里的其他人相同的结论(CIFS + inotify = 不行)。
然而,由于我的工作流程碰巧依赖于远程挂载和依赖 inotify 的自动编译工具,我最终构建了一个(相当绝望和 hacky)的解决方案,它基本上只是使用轮询来监视更改,然后再次触及相同的文件在已安装的一侧,这似乎会触发 inotify 事件。这不是我最自豪的时刻。
话虽如此,它确实有效,所以,享受吧:http: //github.com/rubyruy/watchntouch
我在使用 Python 脚本监视远程 Windows 目录上的日志文件内容时遇到了类似的问题。
这是我的答案。
从 Unix 映射远程驱动器时,在/etc/fstab
使用//xxx.xxx.xxx.xxx/shareddrive /media/shareddrive cifs username=xxxx,password=xxxx,**directio** 0 0
您可以使用凭证文件来避免使用纯文本密码。
该命令可能会根据 unix 版本而改变,这是在 debian 下测试的。它应该按预期工作。你能告诉我它是否有效吗?我计划在 Java 中实现相同的东西,所以答案也可能对我有用。