本论坛中的其他问题询问如何使Java中的文件不可读。这个问题是不同的。我发现的其他问题指出了如何锁定被读取的文件,但是Files.isReadable(Path)仍然返回true!
在Windows 10上使用Java17,我有一个方法,如果Files.isReadable()返回某个路径的false,它有一个契约要做(或不做)某些事情。我需要测试该方法,因此我需要人为地创建一个Files.isReadable()返回false的文件或目录(最好是每个文件或目录中的一个)。
我尝试在文件上创建一个独占锁:
Path lockedFile = writeString(directory.resolve("locked.txt"), "locked");
try (final FileChannel channel = FileChannel.open(lockedFile, StandardOpenOption.APPEND);
FileLock lock = channel.lock()) {
System.out.println("is locked file readable? " + isReadable(lockedFile));
}然而,isReadable()仍然返回true。
我试过使用File.setReadable()
Path lockedFile = writeString(directory.resolve("locked.txt"), "locked");
lockedFile.toFile().setReadable(false);
System.out.println("is locked file readable? " + isReadable(lockedFile));Files.isReadable()仍然返回true。
对于一个文件,我可以做些什么来使isReadable() 返回 false**?** (特定于Windows的东西是可以接受的,因为我可以设置我的单元测试,只在上运行,但至少我可以测试这个方法)。
发布于 2022-08-02 02:02:32
在Windows 10中,这对我起了作用:
AclFileAttributeView view =
Files.getFileAttributeView(path, AclFileAttributeView.class);
view.setAcl(Collections.emptyList());为了实现跨操作系统的完整性,您可以使用适当的检查来保护它,并为(大多数) Unix文件系统添加类似的内容:
FileStore store = Files.getFileStore(path);
if (store.supportsFileAttributeView(AclFileAttributeView.class)) {
AclFileAttributeView view =
Files.getFileAttributeView(path, AclFileAttributeView.class);
view.setAcl(Collections.emptyList());
} else if (store.supportsFileAttributeView(PosixFileAttributeView.class)) {
Files.setPosixFilePermissions(path,
EnumSet.noneOf(PosixFilePermission.class));
}发布于 2022-08-01 22:58:58
可以说,在测试任何与任何类型的文件系统相关的文件系统时,“覆盖字段”的解决方案是来编写您自己的文件系统。好的,好的。清除蚊子可能有点像火箭筒,但是,这个原则几乎扩展到了所有您想要做的事情,并使用文件系统进行测试。
例如,希望有一些代码来写出一个文件,并且您想要检查它是否确实写入了正确的数据?您可以直接创建该文件,但现在您确实需要担心在测试期间要写入的某个目录。文件系统访问也很慢,这也意味着您需要担心测试后的清理工作。为了可并行化的目的,也很难将它们隔离开来。所有这些东西充其量都是小烦恼,但它开始感觉像死亡与一千个削减。
您所做工作的另一个主要缺点是,文件系统的本质在体系结构/操作系统之间差异很大。例如,您可以使用AclFileAttributeView view = Files.getFileAttributeView(path, AclFileAttributeView.class); view.setAcl(Collections.emptyList());,如果您在支持和设置文件系统上支持基于acl的访问系统的概念的操作系统上,这可能会导致.isReadable返回false。
这导致了一个相当糟糕的结果:每次在硬件上运行的代码都是完美的,但是在不同平台上工作的伙伴不能使用代码。如果您不想这样做,虚拟文件系统可以为您修复这个问题。
写我自己的.。什么?
“新”文件IO (java.nio.file )相对于旧的文件IO( java.io )的优点之一是,文件系统大多是抽象出来的。
“文件系统”的概念是你需要定义的东西。因此,您可以定义一个完全在内存中操作的测试--您现在不再需要担心清理,它将尽可能快,如果您想要它们,它将独立于任何其他测试。它也使嘲笑的东西(‘嘲笑’,英语单词,而不是‘嘲弄’,如JMock)容易得多。
有点像时间问题,您必须始终使用正确的调用(即,如果您习惯于在源中调用LocalDate.now(),则需要将其切换到LocalDate.now(clock),以便能够为稳定的测试设置虚拟时钟)。您不能只在任何地方使用Paths.get() -- Path对象“编码”使用的是哪个文件系统(您希望它“编码”您的测试文件系统正在使用中)。
而不是Paths.get("/path/stuff"),您必须调用:
someFileSystem.getPath("/path/stuff")中,someFileSystem可以是FileSystems.getDefault(),这会使您获得与Paths.get相同的行为,但是需要注入它,以便在测试条件下,您可以将它作为您的测试文件系统。
现在你只需要一个假的文件系统。不幸的是,FileSystem API非常复杂。做自己的事可不是件小事。幸运的是,你不必刮这头牦牛毛;有人(具体来说是谷歌的开发团队)已经帮你刮过胡子了。展示JimFS!
不利方面
Paths.get("/x/y")需要被列入你的林特禁令名单;消除这一点可能需要相当多的重写。特别是如果您不使用依赖注入框架。设置一个简单的单例文件系统是值得的;在此基础上,它可以返回FileSystems.getDefault(),然后所有代码的工作方式都是相同的。然后您可以展开它,例如添加一个全局的‘用我的虚拟文件系统覆盖’选项,或者使用ThreadLocal允许每个线程得到自己的线程,无论您需要什么。java.io)的使用,特别是包括使用path.toFile()的尝试,都是行不通的。据我所知,旧的API仅能与实际的文件系统交互。因此,您还需要对代码库中任何地方使用的旧j.i.File进行搜索,并将其替换为基于fileSystem.getPath的代码。如果感觉这是一条更加艰难的道路,而不是您当前的模拟j.n.f.Files类的解决方案,这是可以理解的。你会知道的,这是你的计划。但是,我认为这包括了两个主要选项:模拟所有的东西,或者使用测试文件系统。
https://stackoverflow.com/questions/73199975
复制相似问题