WatchService / WatchEvent / 事件路径

发布于 2024-12-17 09:32:26 字数 1274 浏览 1 评论 0原文

我正在递归地监视目录(以及所有子目录和文件)的更改。

看起来,如果我在 root-dir 的子目录中创建或删除目录或文件来观察 WatchEvent 实例中包含的路径(通过 context())接收到的路径没有父级,因此 rootDirToWatch .resolve(event.context()) 没有返回我喜欢的路径。

例如:

观看 /home/johannes/test ,然后我在 /home/johannes/test/foo/bar 中创建一个名为 baz 的新目录,我得到一个新的 Path 实例,它是 /home/johannes/test/baz 而不是 /home/johannes/test/foo/bar/baz

有什么建议吗?

我只是使用访问者来监视要观看的某个根目录中的所有子目录(监视整个目录及其所有子目录):

@Override
public FileVisitResult preVisitDirectory(final Path pDir, final BasicFileAttributes pAttrs)
    throws IOException
{
    checkNotNull(pDir);
    checkNotNull(pAttrs);
    pDir.register(mWatcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
    return FileVisitResult.CONTINUE;
}

编辑:我认为我真的必须使用访问者或至少将所有子目录注册为观察者。由于 WatchEvent 返回一个相对路径,很清楚为什么它的行为如所描述的那样,但我不想再次遍历该目录以查找从 root-dir 到监视到层次结构中某个位置的添加/删除/修改的文件的路径。

编辑:我找到了解决方案(“索引”键): http://docs.oracle.com/javase/tutorial/displayCode.html?code=http://docs.oracle.com/javase/tutorial/essential/io/examples/WatchDir.java< /a>

I'm recursively watching a directory (and therefore all subdirs and files) for changes.

It seems, if I'm creating or deleting a directory or file in a subdirectory of the root-dir to watch the Path which is included in the WatchEvent instance one receives (via context()) has no Parent and therefore rootDirToWatch.resolve(event.context()) is not returning the Path I like to have.

For instance:

/home/johannes/test is watched, then I'm creating a new directory in /home/johannes/test/foo/bar named baz, I'm getting a new Path instance which is
/home/johannes/test/baz instead of /home/johannes/test/foo/bar/baz

Any suggestions what's going wrong?

I'm simply using a visitor to watch for all subdirectories in a certain root-directory to watch (watching a whole directory with all it's descendants):

@Override
public FileVisitResult preVisitDirectory(final Path pDir, final BasicFileAttributes pAttrs)
    throws IOException
{
    checkNotNull(pDir);
    checkNotNull(pAttrs);
    pDir.register(mWatcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
    return FileVisitResult.CONTINUE;
}

Edit: I think I really have to use a visitor or at least register all subdirs with the watcher. As WatchEvent returns a relative path it's clear why it behaves as described, but I don't want to traverse the directory once more to find the path from the root-dir to watch to the added/deleted/modified File somewhere depper in the hierarchy.

Edit: I've found the solution ("indexing" the keys): http://docs.oracle.com/javase/tutorial/displayCode.html?code=http://docs.oracle.com/javase/tutorial/essential/io/examples/WatchDir.java

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

后知后觉 2024-12-24 09:32:26

艾伦是对的。

您应该在密钥中使用 Watchable。

这是我的应用程序中的 Scala 代码。我想你一定能读懂它。

object FsNotifType extends Enumeration {
  val Create, Update, Delete = Value
}

case class FsNotif(notifType: FsNotifType.Value,path: Path)

object FsNotif {
  def apply(watchKey: WatchKey,event: java.nio.file.WatchEvent[_]): FsNotif = {
    val fsNotifType = event.kind() match {
      case StandardWatchEventKinds.ENTRY_CREATE => FsNotifType.Create
      case StandardWatchEventKinds.ENTRY_MODIFY => FsNotifType.Update
      case StandardWatchEventKinds.ENTRY_DELETE => FsNotifType.Delete
      case _ => throw new IllegalStateException("Unknown FS event kind: " + event)
    }
    val watchedPath = watchKey.watchable().asInstanceOf[Path]
    val relativePath = event.context().asInstanceOf[Path]
    val absolutePath = watchedPath.resolve(relativePath)
    FsNotif(fsNotifType,absolutePath)
  }
}

这工作正常,但要注意一些极端情况:

/**
 * Returns the object for which this watch key was created. This method will
 * continue to return the object even after the key is cancelled.
 *
 * <p> As the {@code WatchService} is intended to map directly on to the
 * native file event notification facility (where available) then many of
 * details on how registered objects are watched is highly implementation
 * specific. When watching a directory for changes for example, and the
 * directory is moved or renamed in the file system, there is no guarantee
 * that the watch key will be cancelled and so the object returned by this
 * method may no longer be a valid path to the directory.
 *
 * @return the object for which this watch key was created
 */
Watchable watchable();

抱歉,我不知道如何处理这个问题。

Alan is right.

You should use the Watchable in the key.

Here's a Scala code from my app. I guess you will be able to read it.

object FsNotifType extends Enumeration {
  val Create, Update, Delete = Value
}

case class FsNotif(notifType: FsNotifType.Value,path: Path)

object FsNotif {
  def apply(watchKey: WatchKey,event: java.nio.file.WatchEvent[_]): FsNotif = {
    val fsNotifType = event.kind() match {
      case StandardWatchEventKinds.ENTRY_CREATE => FsNotifType.Create
      case StandardWatchEventKinds.ENTRY_MODIFY => FsNotifType.Update
      case StandardWatchEventKinds.ENTRY_DELETE => FsNotifType.Delete
      case _ => throw new IllegalStateException("Unknown FS event kind: " + event)
    }
    val watchedPath = watchKey.watchable().asInstanceOf[Path]
    val relativePath = event.context().asInstanceOf[Path]
    val absolutePath = watchedPath.resolve(relativePath)
    FsNotif(fsNotifType,absolutePath)
  }
}

This works fine, but take care of some corner cases:

/**
 * Returns the object for which this watch key was created. This method will
 * continue to return the object even after the key is cancelled.
 *
 * <p> As the {@code WatchService} is intended to map directly on to the
 * native file event notification facility (where available) then many of
 * details on how registered objects are watched is highly implementation
 * specific. When watching a directory for changes for example, and the
 * directory is moved or renamed in the file system, there is no guarantee
 * that the watch key will be cancelled and so the object returned by this
 * method may no longer be a valid path to the directory.
 *
 * @return the object for which this watch key was created
 */
Watchable watchable();

Sorry, I don't know how to deal with this.

世界等同你 2024-12-24 09:32:26

watchable() 方法将返回原始的 Watchable,因此您可以将其用作父目录。

The watchable() method will return the original Watchable so you can use it as the parent directory.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文