Java 1.6 - определение символических ссылок

В классе DirectoryWalker я хочу узнать, действительно ли экземпляр File является символической ссылкой на каталог (при условии, что ходок работает в системах UNIX). Учитывая, что я уже знаю, что экземпляр является каталогом, может ли быть следующим условием для определения символической ссылки?

File file;
// ...      
if (file.getAbsolutePath().equals(file.getCanonicalPath())) {
    // real directory ---> do normal stuff      
}
else {
    // possible symbolic link ---> do link stuff
}

Ответ 1

Техника, используемая в Apache Commons, использует канонический путь к родительскому каталогу, а не к самому файлу. Я не думаю, что вы можете гарантировать, что несоответствие связано с символической ссылкой, но это хороший признак того, что файл нуждается в специальном лечении.

Это код Apache (при условии их лицензия), модифицированный для компактности.

public static boolean isSymlink(File file) throws IOException {
  if (file == null)
    throw new NullPointerException("File must not be null");
  File canon;
  if (file.getParent() == null) {
    canon = file;
  } else {
    File canonDir = file.getParentFile().getCanonicalFile();
    canon = new File(canonDir, file.getName());
  }
  return !canon.getCanonicalFile().equals(canon.getAbsoluteFile());
}

Ответ 2

Java 1.6 не обеспечивает такой низкий уровень доступа к файловой системе. Похоже, NIO 2, который должен быть включен в Java 1.7, будет поддерживать символические ссылки. Доступен проект нового API. Символические ссылки упоминаются там, создание и после их возможно. Я не совсем уверен, что какой метод следует использовать, чтобы выяснить, является ли файл символической ссылкой. Там список рассылки для обсуждения NIO 2 - может быть, они будут знать.

Ответ 3

Также следите за тем, чтобы file.isFile() и file.isDirectory() возвращали результаты на основе разрешенного файла и поэтому возвращали false, когда file ссылается на символическую ссылку, где цель не существует.

(Я знаю, что это не самый полезный ответ сам по себе, но он несколько раз опрокинул меня, поэтому я подумал, что должен поделиться)

Ответ 4

Похоже, getCanonicalPath() может делать другие вещи, которые могут отличить его от абсолютного пути.

Этот метод сначала преобразует этот путь в абсолютную форму, если это необходимо, как если бы он вызывал метод getAbsolutePath(), а затем сопоставлял его с его уникальной формой зависящим от системы образом. Обычно это связано с удалением избыточных имен, таких как ".". и ".." из имени пути, разрешения символических ссылок (на платформах UNIX) и преобразования букв дисков в стандартный пример (на платформах Microsoft Windows).

Но это может сработать для подавляющего большинства ваших случаев использования; ваш пробег может меняться.

Ответ 5

Если вы уже кодируете что-то специально для * nix, тогда вы можете сделать команду оболочки из Java следующим образом:

Process p = Runtime.getRuntime().exec(new String[]{"test", "-h", yourFileName});
p.waitFor();
if (p.exitValue() == 0) 
   System.out.println("This file is a symbolic link");
else
   System.out.println("This file is not a symbolic link");

Это очень специфично для * nix, но, по крайней мере, работает.

Ответ 6

Извините, что ответил на такое старое сообщение, но некоторое время назад искал решение для систем Windows, и некоторые из предыдущих ответов не сработали для меня. Если вам не нужна совместимость с кросс-платформой и требуется только решение для Windows, следующий метод работал хорошо для моих целей.

File f = new File("whatever file or folder");
if (f instanceof ShellFolder) {
  ShellFolder sf = (ShellFolder)f;
  if (sf.isLink()) {
    // Your code when it a link
  }
}

Ответ 7

Я думал, что поделился бы некоторой удачей, с которой я столкнулся с этой проблемой. Я использую JDK 1.6.0_23, поэтому я не могу воспользоваться NIO2. Я только создаю и запускаю Windows 7/x64, поэтому пробег может отличаться в других средах. К сожалению, другие решения здесь не сработали для меня, избегая NullPointerExceptions, возникающих при попытке пересечения перехода (возможно, потому что соединение!= Символическая связь....). Хотя я не ограничена версией JDK, я решил немного продолжить эту проблему.

У меня был этот код, который вызвал бы исключение NullPointerException, если он используется в символической ссылке или когда вы сталкиваетесь с каталогом "Сведения о системном томе". (Обратите внимание: traverseItem.f() возвращает объект типа java.io.File)

if (traverseItem.f().isDirectory) {
    for (File item : traverseItem.f().listFiles()) {

Итак, это, предположительно, каталог, но вызов listFiles() на нем вызывает NPE. Что делать? Я попробовал метод list() и задался вопросом, будет ли он демонстрировать такое же поведение. Я обнаружил следующее:

Вызывающий список() в файле, описывающем пустую папку, возвращает массив String [] с нулевой длиной. Однако вызов списка() в файле, описывающем соединение, которое в противном случае вышло бы из списка listFiles(), возвращает null

Мне удалось избежать NullPointerExceptions, добавив следующий тест перед вызовом listFiles()

    String[] contents = traverseItem.f().list();
    if (contents != null) {  //Non-traversible if null, possibly junction or ???

Остается исчерпывающим образом проверить все случаи соединения, символическую ссылку, жесткую ссылку и осмелюсь упомянуть ее, ярлык, но это может помочь некоторым.