Объединение путей в Java

99

В Pythonсклеить два пути с os.path.join:

os.path.join("foo", "bar") # => "foo/bar"

Я пытаюсь добиться того же на Java, не беспокоясь о том, OSесть ли Unix, Solarisили Windows:

public static void main(String[] args) {
    Path currentRelativePath = Paths.get("");
    String current_dir = currentRelativePath.toAbsolutePath().toString();
    String filename = "data/foo.txt";
    Path filepath = currentRelativePath.resolve(filename);

    // "data/foo.txt"
    System.out.println(filepath);

}

Я ожидал, что Path.resolve( )это присоединится к моему текущему каталогу /home/user/testс data/foo.txtфайлом make /home/user/test/data/foo.txt. Что я ошибаюсь?

кибертекстрон
источник
1
это может быть то, чего я не вижу. Ваш текущий путь - "". Ваш второй путь - «data / foo.txt». Может быть, ваша проблема в том, что вы, кажется, печатаете объект Path вместоfilepath.toString()
cjds
2
Использованиеnew File(parent, child)
saka1029

Ответы:

100

Хотя исходное решение для получения текущего каталога с помощью файла empty Stringработает. Но рекомендуется использовать user.dirсвойство для текущего каталога и user.homeдля домашнего каталога.

Path currentPath = Paths.get(System.getProperty("user.dir"));
Path filePath = Paths.get(currentPath.toString(), "data", "foo.txt");
System.out.println(filePath.toString());

вывод:

/Users/user/coding/data/foo.txt

Из документации по классу пути Java :

Путь считается пустым, если он состоит только из одного элемента имени empty. Доступ к файлу с использованием empty path is equivalent to accessing the default directoryфайловой системы.


Почему Paths.get("").toAbsolutePath()работает

Когда в объект передается пустая строка Paths.get(""), возвращаемый Pathобъект содержит пустой путь. Но когда мы вызываем Path.toAbsolutePath(), он проверяет, больше ли длина пути нуля, в противном случае он используетuser.dir системное свойство и возвращает текущий путь.

Вот код для реализации файловой системы Unix: UnixPath.toAbsolutePath ()


В основном вам нужно создать Pathэкземпляр снова, как только вы разрешите текущий путь к каталогу.

Также я бы предложил использовать File.separatorCharдля независимого от платформы кода.

Path currentRelativePath = Paths.get("");
Path currentDir = currentRelativePath.toAbsolutePath(); // <-- Get the Path and use resolve on it.
String filename = "data" + File.separatorChar + "foo.txt";
Path filepath = currentDir.resolve(filename);

// "data/foo.txt"
System.out.println(filepath);

Вывод:

/Users/user/coding/data/foo.txt
Молодой Хоббит
источник
Не я, может кто-то думает, что работа со строками separatorCharуступает какой-то «абстракции более высокого уровня», что-то вродеPathBuilder(currentRelativePath).append("data").append("foo.txt")
jingyu9575
22

Paths#get(String first, String... more) состояния,

Преобразует строку пути или последовательность строк, которые при соединении образуют строку пути, в Path.

...

A, Pathпредставляющий пустой путь, возвращается, если первая - это пустая строка, а более не содержит непустых строк.

Чтобы получить текущий каталог пользователя, вы можете просто использовать System.getProperty("user.dir").

Path path = Paths.get(System.getProperty("user.dir"), "abc.txt");
System.out.println(path);

Кроме того, getметод использует переменную длину аргумент из String, который будет использоваться , чтобы обеспечить последующие строки пути. Итак, чтобы создать Pathдля /test/inside/abc.txtвас, вы должны использовать его следующим образом:

Path path = Paths.get("/test", "inside", "abc.txt");
CoderCroc
источник
11

Не конкретный метод.

Если вы используете java 8 или выше, у вас есть 2 варианта:

а) Используйте java.util.StringJoiner

StringJoiner joiner = new StringJoiner(File.pathSeparator); //Separator
joiner.add("path1").add("path2");
String joinedString = joiner.toString();

б) Использование String.join(File.pathSeparator, "path1", "path2");

Если вы используете java 7 или ниже, вы можете использовать библиотеку commons-lang из apache commons. У класса StringUtils есть метод соединения строк с помощью разделителя.

в) StringUtils.join(new Object[] {"path1", "path2"}, File.pathSeparator);

Примечание: вы можете использовать разделитель путей Linux "/" для окон (просто помните, что абсолютные пути - это что-то вроде "/ C: / mydir1 / mydir2". Использование всегда "/" очень полезно, если вы используете такие протоколы, как file: //

Робер2Д2
источник
StringJoiner вернул меня/home/user/test:foo.txt
cybertextron
Существуют не только те варианты, о которых вы знаете. Например, можно использовать StringBuilder вместо средства объединения. И на самом деле ваша реализация, основанная на строках, а не на файлах / путях, довольно наивна и приведет к проблемам во многих сценариях.
XenoRo
2
File.separatorработал у меня вместоFile.pathSeparator
Эван Сироки
используйте Pathes.get ("path1", "path2"). toAbsolutePath (). toString ()
Erdinc Ay
6

Самый простой способ:

Path filepath = Paths.get("foo", "bar");

Вы никогда не должны писать Paths.get(""). Я удивлен, что это вообще работает. Если вы хотите явно ссылаться на текущий каталог, используйте Paths.get(System.getProperty("user.dir")). Если вам нужен домашний каталог пользователя, используйте Paths.get(System.getProperty("user.home")).

Также можно комбинировать подходы:

Path filepath = Paths.get(
    System.getProperty("user.home"), "data", "foo.txt");
VGR
источник
1

Самый надежный и независимый от платформы способ соединения путей в Java - это использование Path::resolve(как указано в JavaDoc для Paths::get). Для массива строк произвольной длины, представляющих части пути, они могут быть объединены вместе с помощью Java Stream:

private static final String[] pieces = {
    System.getProperty("user.dir"),
    "data",
    "foo.txt"};
public static void main (String[] args) {
    Path dest = Arrays.stream(pieces).reduce(
    /* identity    */ Paths.get(""),
    /* accumulator */ Path::resolve,
    /* combiner    */ Path::resolve);
    System.out.println(dest);
}
Патрик Паркер
источник