Я создаю программу на 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 является языком, который поддерживает разработку программного обеспечения на самых разных платформах и архитектурах.
как мне открыть
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
относительным или абсолютным. Я не говорю, что это лучше в каком-то абсолютном смысле, но это может иметь преимущества для вас или в чем-то придется вам по вкусу.