«1. Обзор

В этом руководстве мы рассмотрим различные способы создания символической ссылки в Java с использованием API NIO.2 и исследуем различия между жесткими и программными ссылками на файлы.

2. Жесткие и программные/символические ссылки

Во-первых, давайте определим, что такое файловые ссылки и каково их ожидаемое поведение. Ссылка на файл — это указатель, который прозрачно ссылается на файл, хранящийся в файловой системе.

Распространенным заблуждением является мнение, что ссылка на файл — это ярлык, поэтому давайте проверим их поведение:

    Ярлык — это обычный файл, ссылающийся на целевой файл Мягкая/символическая ссылка — это указатель на файл, который ссылается на — если целевой файл удаляется, то ссылка становится непригодной для использования. Жесткая ссылка — это указатель файла, который отражает файл, на который он ссылается, поэтому он в основном похож на клон. Если целевой файл удаляется, файл ссылки все еще действителен

Большинство операционных систем (Linux, Windows, Mac) уже поддерживают программные/жесткие ссылки на файлы, поэтому не должно возникнуть проблем с их обработкой с помощью NIO API. .

3. Создание ссылок

Во-первых, мы должны создать целевой файл для ссылки, поэтому давайте упорядочим некоторые данные в файл:

public Path createTextFile() throws IOException {		
    byte[] content = IntStream.range(0, 10000)
      .mapToObj(i -> i + System.lineSeparator())
      .reduce("", String::concat)
      .getBytes(StandardCharsets.UTF_8);
    Path filePath = Paths.get("", "target_link.txt");
    Files.write(filePath, content, CREATE, TRUNCATE_EXISTING);
    return filePath;		
}

Давайте создадим символическую ссылку на существующий файл, созданный файл является символической ссылкой:

public void createSymbolicLink() throws IOException {
    Path target = createTextFile();
    Path link = Paths.get(".","symbolic_link.txt");
    if (Files.exists(link)) {
        Files.delete(link);
    }
    Files.createSymbolicLink(link, target);
}

Далее давайте рассмотрим создание жесткой ссылки:

public void createHardLink() throws IOException {
    Path target = createTextFile();
    Path link = Paths.get(".", "hard_link.txt");
    if (Files.exists(link)) {
        Files.delete(link);
    }
    Files.createLink(link, target);
}

Перечислив файлы с их различиями, мы увидим, что файл мягкой/символической ссылки размер невелик, а жесткая ссылка занимает то же место, что и связанный файл:

 48K	target_link.txt
 48K	hard_link.txt
4.0K	symbolic_link.txt

Чтобы четко понять, какие возможные исключения могут быть выброшены, давайте посмотрим на проверенные исключения для операций:

    UnsupportedOperationException — когда JVM не поддерживает ссылки на файлы в конкретной системе FileAlreadyExistsException — когда файл ссылки уже существует, переопределение не поддерживается по умолчанию IOException — когда возникает ошибка ввода-вывода, например недопустимый путь к файлу SecurityException — когда файл ссылки не может быть создан или к целевому файлу нет доступа из-за ограниченных прав доступа к файлу

4. Операции со ссылками

Теперь, если у нас есть данная файловая система с существующими ссылками на файлы можно идентифицировать их и показать их целевые файлы:

public void printLinkFiles(Path path) throws IOException {
    try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) {
        for (Path file : stream) {
            if (Files.isDirectory(file)) {
                printLinkFiles(file);
            } else if (Files.isSymbolicLink(file)) {
                System.out.format("File link '%s' with target '%s' %n", 
                  file, Files.readSymbolicLink(file));
            }
        }
    }
}

Если мы выполним его по нашему текущему пути:

printLinkFiles(Paths.get("."));

Мы получим вывод:

File link 'symbolic_link.txt' with target 'target_link.txt'

Примечание. что файлы с жесткими ссылками нельзя просто идентифицировать с помощью API NIO, для работы с такими файлами требуются низкоуровневые операции.

5. Заключение

В этой статье описываются различные типы файловых ссылок, их отличие от ярлыков, а также способы их создания и работы с ними с использованием чистого Java API, который работает с основными файловыми системами на рынке.

Реализацию этих примеров и фрагментов кода можно найти на GitHub.