Java WatchService在Windows上锁定目录

huangapple go评论72阅读模式
英文:

Java WatchService locks directory on Windows

问题

似乎在使用Java的WatchService监视目录后,尝试重命名其父目录时,重命名操作会因为AccessDeniedException而失败。这个目录似乎被WatchService锁定。

可以使用以下代码重现这个问题:

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.nio.file.*;

public class WatcherTest {
    @Test
    public void moveWatchedDir(@TempDir Path tempDir) throws Exception {
        Files.createDirectories(tempDir.resolve("dir1/dir2"));

        var watchService = FileSystems.getDefault().newWatchService();
        tempDir.resolve("dir1/dir2").register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY);

        Files.move(tempDir.resolve("dir1"), tempDir.resolve("dir1_b"));
    }
}

失败信息如下:

java.nio.file.AccessDeniedException: C:\Users\Markus\AppData\Local\Temp\junit14649009910061913524\dir1 -> C:\Users\Markus\AppData\Local\Temp\junit14649009910061913524\dir1_b

	at java.base/sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:89)
	at java.base/sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:103)
	at java.base/sun.nio.fs.WindowsFileCopy.move(WindowsFileCopy.java:395)
	at java.base/sun.nio.fs.WindowsFileSystemProvider.move(WindowsFileSystemProvider.java:292)
	at java.base/java.nio.file.Files.move(Files.java:1426)
	at WatcherTest.moveWatchedDir(WatcherTest.java:13)

在Windows 10上使用OpenJDK 11和14进行了测试。在Windows资源管理器中尝试重命名dir1也会失败。但在Linux上表现正常。

还需要注意的是,如果只在dir1上注册监视器而不在dir1/dir2上注册,操作会成功。

这是否是OpenJDK中的一个错误?根据一些旧问题(https://bugs.openjdk.java.net/browse/JDK-8153925),似乎不应该出现目录锁定的情况。

英文:

It seems when you watch a directory using Java's WatchService and then try to rename its parent directory, the renaming will fail with an AccessDeniedException. The directory seems to be sort of locked by the WatchService.

Can be reproduced with:

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.nio.file.*;

public class WatcherTest {
    @Test
    public void moveWatchedDir(@TempDir Path tempDir) throws Exception {
        Files.createDirectories(tempDir.resolve("dir1/dir2"));

        var watchService = FileSystems.getDefault().newWatchService();
        tempDir.resolve("dir1/dir2").register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY);

        Files.move(tempDir.resolve("dir1"), tempDir.resolve("dir1_b"));
    }
}

Fails with:

java.nio.file.AccessDeniedException: C:\Users\Markus\AppData\Local\Temp\junit14649009910061913524\dir1 -> C:\Users\Markus\AppData\Local\Temp\junit14649009910061913524\dir1_b

	at java.base/sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:89)
	at java.base/sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:103)
	at java.base/sun.nio.fs.WindowsFileCopy.move(WindowsFileCopy.java:395)
	at java.base/sun.nio.fs.WindowsFileSystemProvider.move(WindowsFileSystemProvider.java:292)
	at java.base/java.nio.file.Files.move(Files.java:1426)
	at WatcherTest.moveWatchedDir(WatcherTest.java:13)

Tested with OpenJDK 11 & 14 on Windows 10. Trying to rename dir1 in Windows Explorer also fails.
Works as expected on Linux.

Also note, that when the watcher is not registered on dir1/dir2 but only on dir1 it works.

Is this a bug in OpenJDK? Looking at some older issues (https://bugs.openjdk.java.net/browse/JDK-8153925) it seems that locking of directories should not happen.

答案1

得分: 1

不,这不是一个错误。这是 Windows 的一个称为“强制锁定”的设计特性。无法禁用它。

Linux 使用的是一种称为“咨询性锁定”的方式,这意味着它不会阻止对目录的重命名甚至删除操作。

英文:

No, this is not a bug. It's a design feature of Windows called mandatory locking. There is no way to disable it.

Linux uses advisory locking which means it will not block renames or even deletes of the directory.

答案2

得分: 1

@jurez的回答是正确的,在Windows上,WatchService会锁定目录。这是一个已知的OpenJDK问题(链接:https://bugs.java.com/bugdatabase/view_bug.do?bug_id=7052697),而且显然无法修复。

但是有一个很好的解决方法。在Windows上,可以在不必像在Linux上手动注册每个子目录的监视器的情况下,监视整个目录结构。

这应该可以解决许多情况下的问题。通过这种解决方法,我只需要监视/锁定顶级目录,这不应该会给用户造成问题。

英文:

@jurez answer is correct, on Windows the WatchService will lock directories. This is a known OpenJDK issue and apparently can't be fixed.

But there is a great workaround. On Windows it is possible to watch an entire directory structure without having to manually register watchers for each sub dir as on Linux.

This should solve this issue in many situations. With this workaround I only need to watch/lock the top level dir, which should not cause issues for users.

huangapple
  • 本文由 发表于 2020年9月11日 18:02:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/63844886.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定