为啥 Files.isHidden(Path) 为 Windows 上的目录返回 false?
Posted
技术标签:
【中文标题】为啥 Files.isHidden(Path) 为 Windows 上的目录返回 false?【英文标题】:Why does Files.isHidden(Path) return false for directories on Windows?为什么 Files.isHidden(Path) 为 Windows 上的目录返回 false? 【发布时间】:2019-05-16 10:24:42 【问题描述】:来自Files.isHidden(Path)
的文档(强调我的):
判断文件是否被视为隐藏。隐藏的确切定义取决于平台或提供商。例如,在 UNIX 上,如果文件名以句点字符 ('.') 开头,则认为文件被隐藏。 在 Windows 上,如果文件不是目录并且设置了 DOS 隐藏属性,则认为文件是隐藏的。
根据实现的不同,此方法可能需要访问文件系统以确定文件是否被视为隐藏。
由此我可以理解什么预期的行为。然而,为什么这是预期的行为?
我想知道的原因是Files.isHidden
、DosFileAttributes.isHidden
和 Windows 的文件资源管理器之间的行为差异。例如,我可以进入 文件资源管理器 并将一个目录设置为隐藏,它将不再显示(除非我将其配置为显示隐藏项)。如果我测试是否使用 Java 隐藏了所述目录,则 Files.isHidden
返回 false
和 DosFileAttributes.isHidden
返回 true
。您可以使用以下代码对此进行测试:
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.DosFileAttributes;
public class Main
public static void main(String[] args) throws Exception
final var directory = Path.of(args[0]).toAbsolutePath().normalize();
final var store = Files.getFileStore(directory);
final var dosAttrs = Files.readAttributes(directory, DosFileAttributes.class);
System.out.println("Directory : " + directory);
System.out.println("FileStore : " + store.name() + " [" + store.type() + "]");
System.out.println("Hidden (Files): " + Files.isHidden(directory));
System.out.println("Hidden (Dos) : " + dosAttrs.isHidden());
注意:我使用的是 Windows 10 和 OpenJDK 11.0.1。我的文件系统是 NTFS。
运行这个:
java Main.java C:\path\to\hidden\directory
我明白了:
Directory : C:\path\to\hidden\directory
FileStore : OS [NTFS]
Hidden (Files): false
Hidden (Dos) : true
注意:此行为似乎是 WindowsFileSystemProvider
的一部分。方法Files.isHidden(Path)
只是将调用转发给参数的FileSystem
的提供者。实现基本上是:
DosFileAttributes attrs = ...; // get attributes
return !attrs.isDirectory() && attrs.isHidden();
我发现这个(non)-issue (JDK-8170334) 有一条评论说:
我认为我们这里没有错误,因为 hidden 属性对目录没有意义。
然而,Windows 上的核心软件 File Explorer 的行为就像 hidden 属性在目录上 not 毫无意义。再说一遍,为什么 Windows 上的 Java 实现会考虑 Path
是否指向目录?还是 Java 是正确的,而 文件资源管理器 正在做非标准的事情?
我倾向于认为 File Explorer 是正确的,因为 CMD(通过 dir
)和 PowerShell(通过 Get-ChildItem
) 也不会列出隐藏目录;除非指定了适当的选项,否则不会。
【问题讨论】:
我不是 Java 开发人员,也不打算深入研究 JDK 设计问题,但从表面上看,这在我看来就像有人混淆了 hidden 和 readonly 属性。 Windows shell (Explorer) 会忽略在目录上设置 readonly 属性,因为它没有用。它所做的只是防止删除一个空目录。相比之下,在 Linux/BSD 中的目录上设置不可变属性(通过 chattr / chflags,通常作为超级用户)可以防止以任何方式修改目录。 在我的盒子 "C:\" 上使用 dosAttrs.isHidden() 时要小心,返回 True @Stig 此处相同(Java 12.0.1,Windows 10)。但是,PowerShell 还说"C:\"
是隐藏的,所以这可能是预期的行为。
我同意这不是一个错误,但它会让大多数人感到惊讶。
【参考方案1】:
我检查了documentation 以获取 Microsoft 为 Windows 平台提供的文件属性。它说如果设置了属性FILE_ATTRIBUTE_HIDDEN = 2 (0x2)
文件或目录被隐藏。它不包含在普通目录列表中。
正如我在 sun.nio.fs.WindowsConstants
类中看到的那样,DosFileAttributes.isHidden() 方法使用了相同的值定义 - public static final int FILE_ATTRIBUTE_HIDDEN = 0x00000002;
在我的理解中应该与 Windows 可用的属性一一对应,所以在目录的一般hidden
标志应该以与常规文件相同的方式工作。
关于操作系统/文件系统集成,这种行为似乎是不正确的。
【讨论】:
纠正Files.isHidden()
错误将破坏现有的Windows Java 应用程序,这些应用程序尽职尽责地遵循其对Windows 系统上的隐藏目录的错误定义,而无需进一步检查DosFileAttributes.isHidden()
。这可能是 Java API 开发人员不想让它成为问题的原因,因为我们仍然可以使用 DosFileAttributes.isHidden()
来弥补正确的行为。
我最终提交了一个错误报告:JDK-8215467。我们会看看情况如何,但@ecle 可能是正确的,并且由于他们的评论中解释的原因,它不会被修复;如果它没有像其他两个错误报告那样被关闭为“不是问题”。
原来这是一个错误。报告称它已在 Java 13 中修复。以上是关于为啥 Files.isHidden(Path) 为 Windows 上的目录返回 false?的主要内容,如果未能解决你的问题,请参考以下文章
即使路径不存在,为啥 Path(...).exists 为真? [复制]
为啥 Powershell 环境 PATH 与系统环境 PATH 不同?