java.nio.file.Files 的哪些方法遵循符号链接,哪些不遵循符号链接?



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

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

  • Files.isDirectory(Path, LinkOption...)
  • Files.isRegular(Path, LinkOption...)
  • Files.getAttribute(Path, String, LinkOption...)
  • Files.getLastModified(Path, LinkOption...)
  • Files.getOwner(Path, LinkOption...)
  • Files.getPosixFilePermission(Path, LinkOption...)

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

  • Files.isSymbolicLink(Path)
  • Files.isExecutable(Path)
  • Files.isReadable(Path)
  • Files.isWritable(Path)
  • Files.isHidden(Path)
  • Files.size(Path)
  • Files.getFileStore(Path)

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

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)方法委托给java.nio.file.spi.FileSystemProvider.isHidden(Path)的实现,javadoc 没有指定该方法是否遵循符号链接。

在 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);

}

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

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)在大多数文件系统实现中使用符号链接跟随。

最新更新