TLDR:在大多数情况下,这似乎是FileSystemProvider 实现选择是否遵循符号链接(这可能会回答“为什么”问题)。符号链接是:
已关注:
主要关注:
-
Files.getFileStore(Path) :在 Windows 和 Linux 上关注,在 Jimfs 上没有关注
未关注:
大部分没有被关注:
-
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 上,它是 implemented by following symbolic links,见第 465 行(WindowsFileAttributes.get(file, true) 调用中的 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 上,这个方法是 implemented without following symbolic links(它只检查文件是否以“.”开头):
@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() 调用中的true 参数)来构造UnixFileStore:
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) 在大多数文件系统实现中使用符号链接跟随。