java watcher service_java-我可以使用WatchService监视单个文件的更改(不是整个目录)吗?...

本文探讨了如何在Java中使用WatchService监控单个文件的变化,而非整个目录。作者提供了7种方法,包括注册目录、筛选事件、背景线程处理等,让读者理解如何通过监听目录间接监视文件变动并执行相应操作。
摘要由CSDN通过智能技术生成

java-我可以使用WatchService监视单个文件的更改(不是整个目录)吗?

当我尝试注册文件而不是目录时,将引发java.nio.file.NotDirectoryException。 我可以听一个文件更改,而不听整个目录吗?

7个解决方案

82 votes

只需过滤目录中所需文件的事件即可:

final Path path = FileSystems.getDefault().getPath(System.getProperty("user.home"), "Desktop");

System.out.println(path);

try (final WatchService watchService = FileSystems.getDefault().newWatchService()) {

final WatchKey watchKey = path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);

while (true) {

final WatchKey wk = watchService.take();

for (WatchEvent> event : wk.pollEvents()) {

//we only register "ENTRY_MODIFY" so the context is always a Path.

final Path changed = (Path) event.context();

System.out.println(changed);

if (changed.endsWith("myFile.txt")) {

System.out.println("My file has changed");

}

}

// reset the key

boolean valid = wk.reset();

if (!valid) {

System.out.println("Key has been unregisterede");

}

}

}

在这里,我们检查更改后的文件是否为“ myFile.txt”,如果执行则执行任何操作。

Boris the Spider answered 2019-10-13T19:29:11Z

19 votes

不,无法注册文件,监视服务无法以这种方式工作。 但是注册目录实际上会监视目录子目录(文件和子目录)的更改,而不是目录本身的更改。

如果要观看文件,请在观看服务中注册包含目录。 Path.register()文档说:

WatchKey java.nio.file.Path.register(WatchService watcher,Kind [] events,Modifier ...   修饰符)引发IOException

使用监视服务注册此路径中的文件。

在此版本中,此路径查找存在的目录。 该目录已在监视服务中注册,以便可以监视目录中的条目

然后,您需要处理条目事件,并通过检查事件的上下文值来检测与您感兴趣的文件相关的事件。 上下文值表示条目的名称(实际上是条目的路径相对于其父路径的路径,这恰好是子名称)。 您在这里有一个例子。

mins answered 2019-10-13T19:30:08Z

15 votes

其他答案是正确的,您必须监视目录并筛选特定文件。 但是,您可能希望线程在后台运行。 接受的答案可以在new FileWatcher(new File("/home/me/myfile")).start()上无限期阻止,并且不会关闭WatchService。 适用于单独线程的解决方案可能如下所示:

public class FileWatcher extends Thread {

private final File file;

private AtomicBoolean stop = new AtomicBoolean(false);

public FileWatcher(File file) {

this.file = file;

}

public boolean isStopped() { return stop.get(); }

public void stopThread() { stop.set(true); }

public void doOnChange() {

// Do whatever action you want here

}

@Override

public void run() {

try (WatchService watcher = FileSystems.getDefault().newWatchService()) {

Path path = file.toPath().getParent();

path.register(watcher, StandardWatchEventKinds.ENTRY_MODIFY);

while (!isStopped()) {

WatchKey key;

try { key = watcher.poll(25, TimeUnit.MILLISECONDS); }

catch (InterruptedException e) { return; }

if (key == null) { Thread.yield(); continue; }

for (WatchEvent> event : key.pollEvents()) {

WatchEvent.Kind> kind = event.kind();

@SuppressWarnings("unchecked")

WatchEvent ev = (WatchEvent) event;

Path filename = ev.context();

if (kind == StandardWatchEventKinds.OVERFLOW) {

Thread.yield();

continue;

} else if (kind == java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY

&& filename.toString().equals(file.getName())) {

doOnChange();

}

boolean valid = key.reset();

if (!valid) { break; }

}

Thread.yield();

}

} catch (Throwable e) {

// Log or rethrow the error

}

}

}

我尝试从接受的答案和本文中进行工作。 您应该能够将此线程与new FileWatcher(new File("/home/me/myfile")).start()一起使用,并通过在该线程上调用stopThread()来停止该线程。

timrs2998 answered 2019-10-13T19:30:39Z

9 votes

Apache提供了具有lastModified()方法的FileWatchDog类。

private class SomeWatchFile extends FileWatchdog {

protected SomeWatchFile(String filename) {

super(filename);

}

@Override

protected void doOnChange() {

fileChanged= true;

}

}

在任何需要的地方都可以启动此线程:

SomeWatchFile someWatchFile = new SomeWatchFile (path);

someWatchFile.start();

FileWatchDog类轮询文件的lastModified()时间戳。 Java NIO的本机WatchService效率更高,因为通知是即时的。

idog answered 2019-10-13T19:31:17Z

6 votes

您不能直接观看单个文件,但可以过滤掉不需要的文件。

这是我的FileWatcher类实现:

import java.io.File;

import java.nio.file.*;

import java.nio.file.WatchEvent.Kind;

import static java.nio.file.StandardWatchEventKinds.*;

public abstract class FileWatcher

{

private Path folderPath;

private String watchFile;

public FileWatcher(String watchFile)

{

Path filePath = Paths.get(watchFile);

boolean isRegularFile = Files.isRegularFile(filePath);

if (!isRegularFile)

{

// Do not allow this to be a folder since we want to watch files

throw new IllegalArgumentException(watchFile + " is not a regular file");

}

// This is always a folder

folderPath = filePath.getParent();

// Keep this relative to the watched folder

this.watchFile = watchFile.replace(folderPath.toString() + File.separator, "");

}

public void watchFile() throws Exception

{

// We obtain the file system of the Path

FileSystem fileSystem = folderPath.getFileSystem();

// We create the new WatchService using the try-with-resources block

try (WatchService service = fileSystem.newWatchService())

{

// We watch for modification events

folderPath.register(service, ENTRY_MODIFY);

// Start the infinite polling loop

while (true)

{

// Wait for the next event

WatchKey watchKey = service.take();

for (WatchEvent> watchEvent : watchKey.pollEvents())

{

// Get the type of the event

Kind> kind = watchEvent.kind();

if (kind == ENTRY_MODIFY)

{

Path watchEventPath = (Path) watchEvent.context();

// Call this if the right file is involved

if (watchEventPath.toString().equals(watchFile))

{

onModified();

}

}

}

if (!watchKey.reset())

{

// Exit if no longer valid

break;

}

}

}

}

public abstract void onModified();

}

要使用此方法,您只需要像这样扩展和实现onModified()方法:

import java.io.File;

public class MyFileWatcher extends FileWatcher

{

public MyFileWatcher(String watchFile)

{

super(watchFile);

}

@Override

public void onModified()

{

System.out.println("Modified!");

}

}

最后,开始查看文件:

String watchFile = System.getProperty("user.home") + File.separator + "Desktop" + File.separator + "Test.txt";

FileWatcher fileWatcher = new MyFileWatcher(watchFile);

fileWatcher.watchFile();

BullyWiiPlaza answered 2019-10-13T19:32:01Z

5 votes

我围绕Java 1.7的WatchService创建了一个包装器,该包装器允许注册目录和任意数量的glob模式。 此类将负责过滤,并且仅发出您感兴趣的事件。

try {

DirectoryWatchService watchService = new SimpleDirectoryWatchService(); // May throw

watchService.register( // May throw

new DirectoryWatchService.OnFileChangeListener() {

@Override

public void onFileCreate(String filePath) {

// File created

}

@Override

public void onFileModify(String filePath) {

// File modified

}

@Override

public void onFileDelete(String filePath) {

// File deleted

}

},

, // Directory to watch

, // E.g. "*.log"

, // E.g. "input-?.txt"

, // E.g. "config.ini"

... // As many patterns as you like

);

watchService.start(); // The actual watcher runs on a new thread

} catch (IOException e) {

LOGGER.error("Unable to register file change listener for " + fileName);

}

完整的代码在此仓库中。

Hindol answered 2019-10-13T19:32:33Z

3 votes

不确定其他人,但是我抱怨使用基本的WatchService API监视单个文件的更改所需的代码量。 它必须更简单!

这是使用第三方库的几种替代方法:

使用Apache Commons配置

使用Spring框架中的spring-loaded包(暂时没有找到示例实现,但使用起来看起来很简单)

John Rix answered 2019-10-13T19:33:18Z

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值