Преобразование абсолютных путей в относительные в Java

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ: Формирование относительных путей

Если вам нужно быстро и непринужденно получить относительный путь в Java, используйте метод relativize класса Path, который находится в пакете java.nio.file.Paths:

Java
Скопировать код
Path relativePath = Paths.get("ваш/базовый/путь").relativize(Paths.get("ваш/базовый/путь/подвложенная/директория/файл.txt"));
// Возвращает "подвложенная/директория/файл.txt"... Это довольно просто и легко :)

Работая с URL, приведите их к типу URI и используйте метод URI.relativize:

Java
Скопировать код
URI baseUri = new URI("http://ваш-сайт.com/базовый/путь/");
URI fileUri = new URI("http://ваш-сайт.com/базовый/путь/подвложенная/директория/файл.txt");
URI relativeUri = baseUri.relativize(fileUri);
// Возвращает "подвложенная/директория/файл.txt"... Это похоже на магию, но в реальности – технология!
Кинга Идем в IT: пошаговый план для смены профессии

Учет особенностей файловых систем и сложных сценариев

Важно помнить о разнице между файловыми системами и форматами путей для обеспечения кроссплатформенности. Пути следует нормализовать, принимая во внимание различные разделители каталогов. В более сложных ситуациях, таких как символические ссылки или виртуальные файловые системы, используйте Path.normalize:

Java
Скопировать код
Path basePath = Paths.get("ваш/базовый/путь/").normalize();
Path filePath = Paths.get("ваш/базовый/путь/подвложенная/директория/файл.txt").normalize();
Path relativePath = basePath.relativize(filePath);
// Возвращает "подвложенная/директория/файл.txt"... Очень удобно и просто!

Визуализация

Представьте, что у вас на компьютере есть папка Документы (📁) и внутри неё расположена Поддиректория (📂):

Markdown
Скопировать код
Путь к 📁: /Пользователь/Документы
Путь к 📂: /Пользователь/Документы/Рабочие/Отчеты/2021

Наши задача — определить путь от 📁 до 📂:

Java
Скопировать код
Path docPath = Paths.get("/Пользователь/Документы");
Path nestedPath = Paths.get("/Пользователь/Документы/Рабочие/Отчеты/2021");
Path journeyPath = docPath.relativize(nestedPath);

С помощью relativize() находим путь:

Markdown
Скопировать код
🌿🐾: Рабочие/Отчеты/2021

Мы можем рассматривать journeyPath как маршрут в GPS, который помогает избежать лишних движений!

Работа с URL-ами и сложными файловыми системами

URL-ы: Особые случаи

При работе с URL-ами перед использованием relativize их сначала нужно преобразовать в объекты URI. Если в URL присутствуют параметры запроса или фрагменты, исключите их:

Java
Скопировать код
URI baseUri = new URI("http://ваш-сайт.com/базовый/?query=settings#section");
URI fileUri = new URI("http://ваш-сайт.com/базовый/подвложенная/директория/файл.txt?query=settings#section");

// Сохраняем только путь
baseUri = baseUri.resolve(baseUri.getPath());
fileUri = fileUri.resolve(fileUri.getPath());

URI relativeUri = baseUri.relativize(fileUri);
// Возвращает "подвложенная/директория/файл.txt"... Действительно просто, не так ли?

Работа со сложными файловыми системами

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

Java
Скопировать код
if(!basePath.getRoot().equals(filePath.getRoot())) {
  throw new IllegalArgumentException("Если пути лежат на разных корневых дисках или в сетевых ресурсах, прямой относительный путь определить нельзя.");
  // Это похоже на попытку построить маршрут между Марсом и Венерой!
}

Обработка исключений и улучшение производительности

Непредсказуемые исключения

Некоторые сценарии могут вызвать исключение в relativize из-за отсутствия общих элементов в путях. В таких случаях нам потребуется найти альтернативное решение или обработать исключение:

Java
Скопировать код
try {
  Path relativePath = basePath.relativize(filePath);
} catch (IllegalArgumentException ex) {
  // Будем ловить исключения, как кошка ловит лазерный луч! 
}

Производительность имеет значение

При работе со строковыми переменными в Java наиболее оптимальным выбором будет StringBuilder, особенно при выполнении конкатенации в циклах:

Java
Скопировать код
StringBuilder pathBuilder = new StringBuilder();
pathBuilder.append("некоторый");
pathBuilder.append("путь");
String fullPath = pathBuilder.toString();
// Чем больше строк, тем выше производительность!

Полезные материалы

  1. Paths (Java Platform SE 8) — официальная документация Java по классу Paths.
  2. FileUtils (Apache Commons IO 2.7 API) — полезный инструмент для работы с файлами и путями в Apache Commons IO.
  3. File (Java Platform SE 7) — преобразование файла в URI для расширения возможностей.
  4. URI (Java Platform SE 7) — подробное описание метода URI.relativize.
  5. Path (Java Platform SE 8) — объяснение метода Path.relativize.
  6. Java NIO vs. IO – DZone — сравнение Java NIO и IO, полезное чтение.