Как я могу получить путь к файлу относительно другого файла?

Я создаю программу на C, которая должна читать различные файлы в GNU/Linux.

Представьте себе следующую файловую структуру.

root
 |- dir1
 |   |- file1.txt
 |
 |- dir2
     |- file2.txt

Теперь представьте, что я уже получил относительный путь к root/dir1/file1.txt и прочитал следующее содержимое:

Load: ../dir2/file2.txt

...

Я могу сохранить эту строку ../dir2/file2.txt в буфере C, но не могу использовать ее напрямую с чем-то вроде fopen(3), потому что она попытается открыть этот путь относительно каталога, в котором был запущен исполняемый файл.

Такое поведение также происходит при использовании C #include. Путь указывается относительно источника, в котором он был указан, а не пути, по которому был запущен компилятор.

Мой вопрос: как мне открыть file2.txt, зная (относительный) путь к file1.txt и относительный путь, хранящийся в нем? Я думал о том, чтобы получить каталог file1.txt (root/dir1/) и объединить полученный оттуда относительный путь (root/dir1/../dir2/file2.txt), но, возможно, есть лучший способ.

🤔 А знаете ли вы, что...
C является языком, который поддерживает разработку программного обеспечения на самых разных платформах и архитектурах.


1
51
1

Ответ:

Решено

как мне открыть file2.txt, зная (относительный) путь к file1.txt и относительный путь, хранящийся в нем? Я думал о том, чтобы получить каталог file1.txt (root/dir1/) и объединить полученный оттуда относительный путь (root/dir1/../dir2/file2.txt), но, возможно, есть лучший способ.

В C нет стандартных библиотечных функций для манипулирования путями. Однако POSIX определяет некоторые из них, поэтому, если вы можете предположить среду POSIX (и вы отметили Linux, что достаточно близко), то вы можете найти dirname() , basename() и realpath () могут быть вам полезны, хотя и не решают вашу проблему напрямую.

Описываемый вами метод должен отлично работать для правильно сформированных входных данных, в том числе, если известный путь к file1.txt является абсолютным. Я не думаю, что есть более простой способ. Однако вы, вероятно, захотите убедиться, что путь к file2.txt действительно является относительным, прежде чем применять этот подход. Вы также можете рассмотреть возможность проверки того, что компоненты .. второго пути не пытаются выйти за пределы первого компонента первого пути.

Однако если вы можете положиться на POSIX, тогда другой альтернативой будет использование openat():

#include <libgen.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>

// ...

    char *file1_copy = strdup(path_to_file1);   // DO free() this
    char *file1_dirname = dirname(file1_copy);  // DO NOT free() this

    // O_DIRECTORY and O_PATH are optional and Linux-specific
    int dir1fd = open(file1_dirname, O_RDONLY | O_DIRECTORY | O_PATH);
    // ... verify success ...

    free(file1_copy);

    int file2fd = openat(dir1fd, path_to_file2, O_RDONLY);  // Possibly different flags
    // ... verify success ...

    close(dir1fd);

    // And maybe you want that as a stream, in which case:
    FILE *file2 = fdopen(file2fd, "r");
    // ... verify success ...

Обратите внимание, что этот подход работает независимо от того, является ли заданный путь к file2.txt относительным или абсолютным. Я не говорю, что это лучше в каком-то абсолютном смысле, но это может иметь преимущества для вас или в чем-то придется вам по вкусу.


Интересные вопросы для изучения