- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我尝试观察某些文件的更改。但我从 watch_object.watch_service.poll(16, TimeUnit.MILLISECONDS);
获得的 WatchKey
始终为 null
。控制台没有打印任何错误,所以我有点迷失。
public class FileWatcher implements Runnable {
public FileWatcher() {
}
static public class Watch_Object {
public File file;
public WatchService watch_service;
}
static public HashMap<Object, Watch_Object> watched_files = new HashMap<>();
static public boolean is_running = false;
static public synchronized void watch(Object obj, String filename) {
File file = new File(filename);
if (file.exists()) {
try {
WatchService watcher = null;
watcher = FileSystems.getDefault().newWatchService();
Watch_Object watch_object = new Watch_Object();
watch_object.file = file;
watch_object.watch_service = watcher;
watched_files.put(obj, watch_object);
Path path = file.toPath().getParent();
path.register(watcher, StandardWatchEventKinds.ENTRY_MODIFY);
if (!is_running) {
(new Thread(new FileWatcher())).start();
is_running = true;
}
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return;
}
}
else {
// Error
}
}
@Override
public void run() {
try {
while (true) {
synchronized(this) {
for (Watch_Object watch_object : watched_files.values()) {
WatchKey key = watch_object.watch_service.poll(16, TimeUnit.MILLISECONDS);
System.out.println("A");
if (key != null) {
System.out.println("B");
}
}
}
Thread.sleep(16);
}
}
catch (Throwable e) {
// Log or rethrow the error
e.printStackTrace();
}
}
}
运行它:
public static void main(String[] args) {
// the obj is WIP, just use null for now
watch(null, "/Users/doekewartena/Desktop/test_image.png");
}
最佳答案
我想在这个答案前面加上WatchService
高度依赖于实现:
<小时/>Platform dependencies
The implementation that observes events from the file system is intended to map directly on to the native file event notification facility where available, or to use a primitive mechanism, such as polling, when a native facility is not available. Consequently, many of the details on how events are detected, their timeliness, and whether their ordering is preserved are highly implementation specific. For example, when a file in a watched directory is modified then it may result in a single
ENTRY_MODIFY
event in some implementations but several events in other implementations. Short-lived files (meaning files that are deleted very quickly after they are created) may not be detected by primitive implementations that periodically poll the file system to detect changes.If a watched file is not located on a local storage device then it is implementation specific if changes to the file can be detected. In particular, it is not required that changes to files carried out on remote systems be detected.
您提到 WatchService.poll
始终返回 null
。这并不完全令人惊讶,因为 poll()
和 poll(long,TimeUnit)
如果没有要处理的事件,将返回 null - 标准的类似队列的行为。但你说你总是得到null
,即使你修改了监视的文件*。不幸的是,我无法使用 OpenJDK 11.0.2(或 JDK 1.8.0_202)、Windows 10 和本地存储设备重现该问题。
*这是在问题评论被清理之前说的。
在尝试您的代码时,我观察到 B
被打印到控制台。诚然,要看到它并不容易,因为每 16
毫秒打印 A
令人难以承受,但它确实存在。但有一个问题,在第一次修改事件之后,它不会再报告了。这让我对您的代码发表一些评论。
WatchKey.reset()
.处理完 WatchKey
后调用此方法非常重要。该方法将 WatchKey
标记为准备检测新事件。如果没有这个调用,您将无法观察到后续事件。
WatchKey
的。为了解决看不到后续事件的问题,我天真地添加了对 reset()
的调用,而没有执行任何其他操作。这导致大量的 B
被打印到控制台。我很困惑,因为我只修改了一次文件,但后来我阅读了 WatchKey.reset
的文档(强调我的):
Resets this watch key.
If this watch key has been cancelled or this watch key is already in the ready state then invoking this method has no effect. Otherwise if there are pending events for the object then this watch key is immediately re-queued to the watch service. If there are no pending events then the watch key is put into the ready state and will remain in that state until an event is detected or the watch key is cancelled.
我所看到的只是一遍又一遍地发生相同的事件,因为我从未处理过它。添加对 WatchEvent.pollEvents()
的调用后我不再收到 B
的垃圾邮件。
WatchService
。您似乎想要一个可以监视任意数量的文件(并且仅监视这些文件)的类。这不需要每个文件都有一个 WatchService
,因为您可以使用同一个 WatchService
注册多个目录。如果文件来自不同的FileSystem
,则您需要使用多个WatchService
。但是,您的代码始终使用 default file system .
使用相同的 WatchService
也无需使用 poll
。我假设您当前使用poll
的原因是因为您需要检查每个WatchService
。由于现在只有一个,您可以使用阻止 WatchService.take()
方法代替。
这是一个小例子,我相信它可以满足您的需求。我不能保证它是完美的,因为它还没有经过彻底的测试。我也不能保证它可以在您的计算机上运行。
import java.io.Closeable;
import java.io.IOException;
import java.nio.file.ClosedWatchServiceException;
import java.nio.file.FileSystem;
import java.nio.file.Path;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BiConsumer;
/**
* Watches files for modification events, but not for creation,
* deletion, or overflow events.
*/
public class FileWatcher implements Closeable, Runnable {
private final List<BiConsumer<? super FileWatcher, ? super Path>> handlers
= new CopyOnWriteArrayList<>();
private final Object lock = new Object();
private final Map<Path, Registry> registeredDirs = new HashMap<>();
private final Set<Path> watchedFiles = new HashSet<>();
private final AtomicBoolean running = new AtomicBoolean();
private final FileSystem fileSystem;
private final WatchService service;
public FileWatcher(FileSystem fs) throws IOException {
service = fs.newWatchService();
fileSystem = fs;
}
public FileSystem getFileSystem() {
return fileSystem;
}
public boolean startWatching(Path file) throws IOException {
Objects.requireNonNull(file);
synchronized (lock) {
if (watchedFiles.add(file)) {
Path directory = file.getParent();
if (registeredDirs.containsKey(directory)) {
registeredDirs.get(directory).incrementCount();
} else {
try {
WatchKey key = directory.register(service, ENTRY_MODIFY);
registeredDirs.put(directory, new Registry(key));
} catch (ClosedWatchServiceException | IllegalArgumentException
| IOException | SecurityException ex) {
watchedFiles.remove(file);
throw ex;
}
}
return true;
}
return false;
}
}
public boolean stopWatching(Path file) {
Objects.requireNonNull(file);
synchronized (lock) {
if (watchedFiles.remove(file)) {
Path directory = file.getParent();
Registry registry = registeredDirs.get(directory);
if (registry.decrementCount()) {
registeredDirs.remove(directory);
registry.cancelKey();
}
return true;
}
return false;
}
}
public void addHandler(BiConsumer<? super FileWatcher, ? super Path> handler) {
handlers.add(Objects.requireNonNull(handler));
}
public void removeHandler(BiConsumer<? super FileWatcher, ? super Path> handler) {
handlers.remove(Objects.requireNonNull(handler));
}
private void fireModifyEvent(Path source) {
for (BiConsumer<? super FileWatcher, ? super Path> handler : handlers) {
try {
handler.accept(this, source);
} catch (RuntimeException ex) {
Thread.currentThread().getUncaughtExceptionHandler()
.uncaughtException(Thread.currentThread(), ex);
}
}
}
@Override
public void close() throws IOException {
service.close();
synchronized (lock) {
registeredDirs.clear();
watchedFiles.clear();
}
}
@Override
public void run() {
if (running.compareAndSet(false, true)) {
try {
while (!Thread.interrupted()) {
WatchKey key = service.take();
for (WatchEvent<?> event : key.pollEvents()) {
Path source = ((Path) key.watchable())
.resolve((Path) event.context());
boolean isWatched;
synchronized (lock) {
isWatched = watchedFiles.contains(source);
}
if (isWatched) {
fireModifyEvent(source);
}
}
key.reset();
}
} catch (InterruptedException ignore) {
} finally {
running.set(false);
}
} else {
throw new IllegalStateException("already running");
}
}
private static class Registry {
private final WatchKey key;
private int count;
private Registry(WatchKey key) {
this.key = key;
incrementCount();
}
private void incrementCount() {
count++;
}
private boolean decrementCount() {
return --count <= 0;
}
private void cancelKey() {
key.cancel();
}
}
}
还有一个使用上述FileWatcher
的小应用程序:
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class Main {
public static void main(String[] args) throws IOException {
Path file = chooseFile();
if (file == null) {
return;
}
System.out.println("Entered \"" + file + "\"");
ExecutorService executor = Executors.newSingleThreadExecutor();
try (FileWatcher watcher = new FileWatcher(FileSystems.getDefault())) {
Future<?> task = executor.submit(watcher);
executor.shutdown();
watcher.addHandler((fw, path) -> System.out.println("File modified: " + path));
watcher.startWatching(file);
waitForExit();
task.cancel(true);
} finally {
executor.shutdownNow();
}
}
private static Path chooseFile() {
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.print("Enter file (or 'exit' to exit application): ");
String line = scanner.nextLine();
if ("exit".equalsIgnoreCase(line.trim())) {
return null;
}
Path file = Paths.get(line).toAbsolutePath().normalize();
if (Files.isRegularFile(file, LinkOption.NOFOLLOW_LINKS)) {
return file;
}
System.out.println("File must exist and be a regular file. Try again.");
}
}
private static void waitForExit() {
System.out.println("\nType 'exit' to exit the application.");
Scanner scanner = new Scanner(System.in);
while (true) {
String line = scanner.nextLine();
if ("exit".equalsIgnoreCase(line.trim())) {
return;
}
}
}
}
以及它的实际操作的 GIF:
关于java - WatchKey 始终为空,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54749397/
我尝试观察某些文件的更改。但我从 watch_object.watch_service.poll(16, TimeUnit.MILLISECONDS); 获得的 WatchKey 始终为 null。控
我的代码如下: for (;;) { // retrieve key WatchKey key = watcher.take(); // process events for
如果该问题之前已被问过,请指出答案。 我正在 Watching a Directory for Changes 上阅读本教程和 example如果目录(路径)不再可用,则程序应该退出 - 已删除。 只
本文整理了Java中org.uberfire.java.nio.file.WatchKey.reset()方法的一些代码示例,展示了WatchKey.reset()的具体用法。这些代码示例主要来源于G
本文整理了Java中org.uberfire.java.nio.file.WatchKey.pollEvents()方法的一些代码示例,展示了WatchKey.pollEvents()的具体用法。这些
我正在尝试查看对特定文件夹所做的所有修改。当我复制一个包含 2~5 个子文件夹且每个子文件夹有 2~3 个文件的文件夹时。一切都很好。 当我复制复杂的文件夹结构时出现问题。例如,当我复制任何示例 We
Watching Service api ( https://docs.oracle.com/javase/tutorial/essential/io/notification.html ) 看起来有
我是一名优秀的程序员,十分优秀!