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 это реализовано с помощью следующих символических ссылок , см. Строку 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()
):
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)
использует символическую ссылку, следующую в большинстве реализаций файловой системы.