首页 > 解决方案 > java.nio.file.Files 的哪些方法遵循符号链接,哪些不遵循?

问题描述

Java 帮助类java.nio.file.Files具有访问文件属性的方法。一些类方法遵循符号链接(所有方法都有LinkOption参数),而对于其他一些方法,不清楚是否遵循符号链接(没有LinkOption参数的方法)。

以下是一些遵循符号链接的方法:

对于其他一些方法,确定它们是否遵循符号链接并不明显(没有LinkOption...参数,也没有在 javadoc 中提及符号链接):

哪些是LinkOption...遵循符号链接的不带参数的方法,为什么?

标签: javasymlinksymlink-traversal

解决方案


TLDR:在大多数情况下,这似乎是FileSystemProvider遵循符号链接或不遵循符号链接的实现选择(这可能会回答“为什么”问题)。符号链接是:

跟随:

  • Files.size(Path)

主要关注:

  • Files.getFileStore(Path): 在 Windows 和 Linux 上被关注,在 Jimfs 上没有被关注

未关注:

  • Files.isSymbolic(Path)

大多没有遵循:

  • Files.isExecutable(Path): 在 Windows 和 Unix 上没有遵循,但在 Jimfs 上遵循
  • Files.isReadable(Path): 在 Windows 和 Unix 上没有遵循,但在 Jimfs 上遵循

完全实现特定:

  • Files.isWritable(Path): 在 Windows 上紧随其后,但在 Unix 上没有
  • Files.isHidden(Path): 在 Windows 上紧随其后,但在 Unix 上没有

Files.readAttributes(Path, Class, LinkOption...)您可以通过调用和使用返回的属性来确定是否遵循符号链接。

Files.isSymbolic(Path)不遵循符号链接

对于Files.isSymbolic(Path),原因很明显:如果该方法默认遵循符号链接,它总是会返回false

Files.isHidden(Path)在 Windows 上遵循符号链接,但在 Unix 上不遵循

从方法签名,我们可能会认为该方法不遵循符号链接(因为没有LinkOption...参数)。然而,这并不是那么明显。

Files.isHidden(Path)方法委托和 javadoc 的实现java.nio.file.spi.FileSystemProvider.isHidden(Path)没有指定方法是否遵循符号链接。

在 Windows 上,它是通过跟随符号链接实现的,见第 465 行(调用true中的参数WindowsFileAttributes.get(file, true)告诉跟随符号链接):

@Override
public boolean isHidden(Path obj) throws IOException { 
    WindowsPath file = WindowsPath.toWindowsPath(obj); 
    file.checkRead(); 
    WindowsFileAttributes attrs = null; 
    try { 
        attrs = WindowsFileAttributes.get(file, true); 
    } catch (WindowsException x) { 
        x.rethrowAsIOException(file); 
    } 
    // DOS hidden attribute not meaningful when set on directories 
    if (attrs.isDirectory()) 
        return false; 
    return attrs.isHidden(); 
} 

在 Unix 上,这个方法是在不遵循符号链接的情况下实现的(它只检查文件是否以“.”开头):

@Override
public boolean isHidden(Path obj) {
    UnixPath file = UnixPath.toUnixPath(obj);
    file.checkRead();
    UnixPath name = file.getFileName();
    if (name == null)
        return false;
    return (name.asByteArray()[0] == '.');
}

因此,我们可以得出结论,这是特定于实现的。

Files.isExecutable(Path)不要遵循大多数文件系统中的符号链接

此方法委托给Files.isAccessible(Path, AccessMode.EXECUTE),它委托给FileSystemProvider.checkAccess(Path, AccessMode...)方法。

在 Windows 上,该WindowsFileSystemProvider.checkAccess(Path, AccessMode...)方法委托给java.lang.SecurityManager哪个来决定文件是否可执行。AFAIK,SecurityManager不遵循符号链接,因此我们可以假设Files.isExecutable(Path)在 Windows 上不遵循符号链接。

在 Unix 上,该UnixFileSystemProvider.checkAccess(Path, AccessMode...)方法也委托给SecurityManager,我们可以假设它Files.isExecutable(Path)也不遵循 Unix 上的符号链接。

在 Jimfs(来自 Google 的内存文件系统)上,调用代表com.google.common.jimfs.FileSystemView.checkAccess(JimfsPath)遵循符号链接(即使 Jimfs 不支持访问控制):

public void checkAccess(JimfsPath path) throws IOException {
    // just check that the file exists
    lookUpWithLock(path, Options.FOLLOW_LINKS).requireExists(path);
}

因此,我们可以得出结论,Files.isExecutable(Path)可能会根据文件系统遵循符号链接,但在大多数情况下(Unix + Windows)不会。

Files.isReadable(Path)在大多数文件系统上不遵循符号链接

的实现Files.isReadable(Path)非常类似于以下之一isExecutable(Path):不要关注 Unix 和 Windows 上的链接,而是关注 Jimfs 上的链接。

Files.isWritable(Path)

至于Files.isExecutable(Path)isWritable(Path)方法委托给FileSystemProvider.checkAccess(Path).

在 Windows 上,这需要确定文件是否具有只读属性,这可以通过以下链接完成(参见WindowsFileSystemProvider上面的代码)。

在 Unix 上,这显然是在没有遵循符号链接的情况下完成的(见UnixFileSystemProvider上文)。

因此,我们可以得出结论,这是特定于实现的。

Files.size(Path)跟随符号链接

该实现委托给readAttributes,因此它遵循所有文件系统实现的符号链接:

public static long size(Path path) throws IOException {
    return readAttributes(path, BasicFileAttributes.class).size();
}

Files.getFileStore(Path)

该方法委托给该FileSystemProvider.getFileStore(Path)方法。

在 Windows 上,它使用WindowsFileStore.create(Path)以下符号链接(参见true参数):

static WindowsFileStore create(WindowsPath file) throws IOException {
    try {
        // if the file is a link then GetVolumePathName returns the
        // volume that the link is on so we need to call it with the
        // final target
        String target = WindowsLinkSupport.getFinalPath(file, true);
  ...

在 Unix 上,该FileSystemProvider.getFileStore(Path)方法是抽象的并由子类实现,例如[LinuxFileSystem][3]

@Override
LinuxFileStore getFileStore(UnixPath path) throws IOException {
    return new LinuxFileStore(path);

}

此类UnixFileStore通过获取带有链接后的属性(调用true中的参数UnixFileAttributes.get())来构造 a:

private static long devFor(UnixPath file) throws IOException {
    try {
        return UnixFileAttributes.get(file, true).dev();
    } catch (UnixException x) {
        x.rethrowAsIOException(file);
        return 0L;  // keep compiler happy
    }
}

在 Jimfs 中,FileStore似乎在创建时附加到文件中,因此看起来没有遵循链接。

因此,我们可以得出结论,Files.getFileStore(Path)在大多数文件系统实现中使用符号链接跟随。


推荐阅读