kle*_*tra 11 java swing nio swingworker watchservice
WatchService听起来像一个令人兴奋的想法...不幸的是,它似乎与教程/ api plus中警告的低水平并不真正适合Swing事件模型(或者我错过了一些明显的,非零概率
从教程中的 WatchDir 示例中获取代码(只是为了处理单个目录),我基本上结束了
通过使用已删除/创建的文件作为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);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)基本的想法是使用代码幸福地不知道粘糊糊的细节:它监听属性的变化,并根据需要更新任意模型:
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);
Run Code Online (Sandbox Code Playgroud)
似乎工作,但我感到不舒服
[A] 编辑(由@ trashgods的评论引发) - 它实际上不是我必须随事件传递的密钥,它是报告更改的目录.相应地改变了问题
仅供参考,这个问题被交叉发布到OTN摇摆论坛
附录
阅读WatchKey的api文档:
如果有多个线程从监视服务检索已发出信号的密钥,则应注意确保仅在处理完对象的事件后调用reset方法.
似乎暗示事件应该
不完全确定,但结合(未来)要求递归观看目录(不止一个)决定遵循@Eels建议,有点 - 将很快发布我定居的代码
编辑 只是接受了我自己的答案 - 如果有人有合理的反对意见,将谦卑地回复
实际上,@Eels 的评论并没有停止敲击我的脑后 - 并最终注册:这是要走的路,但不需要任何“人工”结构,因为我们已经有了完美的候选者 - 它是 PropertyChangeEvent本身:-)
从我的问题中获取整体流程描述,前三个项目符号保持不变
修改FileWorker:
@SuppressWarnings("unchecked")
public class FileWorker extends SwingWorker<Void, PropertyChangeEvent> {
public static final String FILE_DELETED = StandardWatchEventKinds.ENTRY_DELETE.name();
public static final String FILE_CREATED = StandardWatchEventKinds.ENTRY_CREATE.name();
public static final String FILE_MODIFIED = StandardWatchEventKinds.ENTRY_MODIFY.name();
// final version will keep a map of keys/directories (just as in the tutorial example)
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(createChangeEvent((WatchEvent<Path>) event, key));
}
// reset key return if directory no longer accessible
boolean valid = key.reset();
if (!valid) {
break;
}
}
return null;
}
/**
* Creates and returns the change notification. This method is called from the
* worker thread while looping through the events as received from the Watchkey.
*
* @param event
* @param key
*/
protected PropertyChangeEvent createChangeEvent(WatchEvent<Path> event, WatchKey key) {
Path name = event.context();
// real world will lookup the directory from the key/directory map
Path child = directory.resolve(name);
PropertyChangeEvent e = new PropertyChangeEvent(this, event.kind().name(), null, child.toFile());
return e;
}
@Override
protected void process(List<PropertyChangeEvent> chunks) {
super.process(chunks);
for (PropertyChangeEvent event : chunks) {
getPropertyChangeSupport().firePropertyChange(event);
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4494 次 |
| 最近记录: |