WatchService 听起来像是一个令人兴奋的想法......不幸的是,它似乎像教程/api 中警告的那样低级,而且并不真正适合 Swing 事件模型(或者我错过了一些明显的东西,非零概率
获取代码来自教程中的 WatchDir 示例 http://download.oracle.com/javase/tutorial/essential/io/notification.html(简化为仅处理单个目录),我基本上结束了
- 扩展 SwingWorker
- 在构造函数中进行注册操作
- 将等待按键的无限循环放入 doInBackground
- 通过 key.pollEvents() 检索时发布每个 WatchEvent
-
通过将删除/创建的文件作为 newValue 触发 propertyChangeEvents 来处理块
@SuppressWarnings("unchecked")
public class FileWorker extends SwingWorker<Void, WatchEvent<Path>> {
public static final String DELETED = "deletedFile";
public static final String CREATED = "createdFile";
private Path directory;
private WatchService watcher;
public FileWorker(File file) throws IOException {
directory = file.toPath();
watcher = FileSystems.getDefault().newWatchService();
directory.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
}
@Override
protected Void doInBackground() throws Exception {
for (;;) {
// wait for key to be signalled
WatchKey key;
try {
key = watcher.take();
} catch (InterruptedException x) {
return null;
}
for (WatchEvent<?> event : key.pollEvents()) {
WatchEvent.Kind<?> kind = event.kind();
// TBD - provide example of how OVERFLOW event is handled
if (kind == OVERFLOW) {
continue;
}
publish((WatchEvent<Path>) event);
}
// reset key return if directory no longer accessible
boolean valid = key.reset();
if (!valid) {
break;
}
}
return null;
}
@Override
protected void process(List<WatchEvent<Path>> chunks) {
super.process(chunks);
for (WatchEvent<Path> event : chunks) {
WatchEvent.Kind<?> kind = event.kind();
Path name = event.context();
Path child = directory.resolve(name);
File file = child.toFile();
if (StandardWatchEventKinds.ENTRY_DELETE == kind) {
firePropertyChange(DELETED, null, file);
} else if (StandardWatchEventKinds.ENTRY_CREATE == kind) {
firePropertyChange(CREATED, null, file);
}
}
}
}
基本思想是让使用代码幸福地不知道粘糊糊的细节:它监听属性更改和 f.i.根据需要更新任意模型:
String testDir = "D:\\scans\\library";
File directory = new File(testDir);
final DefaultListModel<File> model = new DefaultListModel<File>();
for (File file : directory.listFiles()) {
model.addElement(file);
}
final FileWorker worker = new FileWorker(directory);
PropertyChangeListener l = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (FileWorker.DELETED == evt.getPropertyName()) {
model.removeElement(evt.getNewValue());
} else if (FileWorker.CREATED == evt.getPropertyName()) {
model.addElement((File) evt.getNewValue());
}
}
};
worker.addPropertyChangeListener(l);
JXList list = new JXList(model);
貌似可以用,但是感觉不舒服
- 我把自己标榜为与线程无关的人:到目前为止,我看到的所有示例片段都通过使用 watcher.take() 来阻塞等待线程。他们为什么这么做?预计至少会有一些人使用 watcher.poll() 并睡一会儿。
- SwingWorker 发布方法似乎不太适合:现在还好,因为我只观看一个目录(不想在错误的方向上走得太远:)当尝试观看多个目录时(如原始 WatchDir 示例)有多个键,并且 WatchEvent 与其中之一相关。要解析路径,我需要事件和目录[A] 关键是看——但只能传一个。不过,很可能逻辑分布是错误的
[A] Edited(由 @trashgods 的评论触发) - 它实际上不是我必须随事件一起传递的密钥,它是报告更改的目录。相应地改变了问题
仅供参考,这个问题被交叉发布到
Addendum
阅读WatchKey的api文档:
有多个线程从手表检索有信号的键
服务然后应注意确保重置方法是
仅在处理对象的事件后调用。
似乎暗示事件应该
- 在检索 WatchKey 的同一线程上进行处理
- 钥匙重置后不应触摸
不完全确定,但结合(未来)递归观看目录(多个)的要求,决定遵循 @Eels 的建议,有点 - 很快就会发布我决定的代码
EDIT刚刚接受了我自己的答案 - 如果有人有合理的反对意见,我会谦虚地回复这一点
因为你的后台线程完全用于观看,take() http://download.oracle.com/javase/7/docs/api/java/nio/file/WatchService.html#take%28%29是正确的选择。它有效地隐藏了平台依赖 http://download.oracle.com/javase/7/docs/api/java/nio/file/WatchService.html实现,可以转发或轮询。中的一个poll() http://download.oracle.com/javase/7/docs/api/java/nio/file/WatchService.html#poll%28%29例如,如果您的后台线程还需要检查与该队列串联的其他队列,则方法将是合适的WatchService
.
附录:因为WatchKey http://download.oracle.com/javase/7/docs/api/java/nio/file/WatchKey.html有状态,它可能不应该被转发到process()
. The context() http://download.oracle.com/javase/7/docs/api/java/nio/file/WatchEvent.html#context%28%29 of a WatchEvent http://download.oracle.com/javase/7/docs/api/java/nio/file/WatchEvent.html is a "relative http://download.oracle.com/javase/7/docs/api/java/nio/file/Path.html#relativize%28java.nio.file.Path%29注册到监视服务的目录与创建、删除或修改的条目之间的路径。”其中之一resolve() http://download.oracle.com/javase/7/docs/api/java/nio/file/Path.html#resolve%28java.nio.file.Path%29如果目录共享公共根,方法应该有效。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)