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