Я пытаюсь открыть файл и прочитать его содержимое. Но в настоящее время я просто пытаюсь открыть его.
Вот мой код:
void read_contents(char* file_path)
{
printf("\nOriginal path: %s\n", file_path);
// Trying to prefix the path with "." to indicate that the path is relative.
char prefix[1024] = ".";
strcat(prefix, file_path);
// Printing to make sure that prefix contains correct path.
printf("\nPath after concatenating: %s\n", prefix);
FILE* file = fopen(prefix, "r");
if (file == NULL)
{
perror("Error");
// Close the file and stop the function.
fclose(file);
return;
}
// Code to read the file...
// ...
// Code to read the file...
fclose(file);
}
Вот вывод: (имейте в виду, что он даже не доходит до части чтения)
Original path: /input_files/file_1.txt
Path after concatenating: ./input_files/file_1.txt
Error: no such file or directory
Вот моя структура каталогов:
root:
executable
input_files (this is a folder)
file_1.txt
Исполняемый файл находится на том же уровне, что и папка с именем «input_files». Внутри input_files находится текстовый файл.
Дополнительные вещи:
При всем этом я все еще получаю сообщение об ошибке, говорящее об отсутствии такого файла или каталога. Может ли кто-нибудь сказать мне, что мне не хватает?
Зачем ты поставил точку впереди? Это полностью меняет смысл пути.
Я добавил "." в начало строки, потому что я пытался выполнить то же самое без него, и я продолжал получать сообщение об ошибке. После некоторых исследований я обнаружил, что, по-видимому, если вы хотите обратиться к текущему каталогу, вам нужно сказать «./» (по крайней мере, в Linux). Вот почему я решил сделать это. Почему? Это неправильно? Если да, то подскажите как это сделать.
Похоже, что ваши настоящие каталоги и файлы имеют дополнительный префикс __. Если это часть имени, вам нужно включить его в строки пути.
Прошу прощения за это, я использовал подчеркивание, чтобы лучше продемонстрировать структуру, подобную дереву. Пожалуйста, игнорируйте начальные символы подчеркивания. Я удалил их на всякий случай.
Если fopen() потерпел неудачу, вы не хотите fclose() этого. Пути, начинающиеся с /, являются абсолютными путями, все остальное относительно. Путь ./x` такой же, как просто x.
Отложите вашу программу в сторону. В том же терминале введите cat ./input_files/file_1.txt. Что вы наблюдаете?
Учитывая вашу настройку, программа должна работать, если выполняется с помощью «./executable». Если вы запустите его, скажем, "../executable", то он не будет работать.
Это действительно расстраивает, я полностью и полностью понимаю, что вы все предлагаете, и ценю это, но по какой-то причине это просто странно. Я даже попробовал предложение для этой команды: cat ./input_files/file_1.txt Когда я выполняю эту команду из терминала из точного местоположения моего исполняемого файла, это фактически дает мне правильные результаты: 10 20 30 В этот момент я потерял дар речи. Если я дам то же самое своей программе, то fopen() скажет, что не может найти файл.
Я проверял путь, расположение исполняемого файла, структуру файла, имена файлов, имена папок и операторы отладки, такие как getcwd(), printf и т. д., снова и снова (27 раз) сейчас и, ради любви ко мне, я не вижу любая разница. И все же команда работает, а fopen() нет. В этот момент я теряю клетки мозга.
просто догадываюсь, есть неправильно истолкованный алгоритм. ИДК, может быть, вы называете это дополнительными пробелами в конце строки или с '\ r', или что-то в этом роде
Пожалуйста, опубликуйте минимальный воспроизводимый пример.





Я не могу воспроизвести ошибку, которая, вероятно, означает, что ваш текущий рабочий каталог, вероятно, отличается от ожидаемого. Вот программа, которую вы должны были предоставить вместо неполного фрагмента, которая распечатает текущий рабочий каталог (cwd):
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
void read_contents(char* file_path) {
printf("Original path: %s\n", file_path);
char prefix[strlen(file_path)+2];
strcpy(prefix, ".");
strcat(prefix, file_path);
printf("Path after concatenating: %s\n", prefix);
FILE* file = fopen(prefix, "r");
if (!file) {
perror("Error");
char cwd[PATH_MAX];
getcwd(cwd, PATH_MAX);
printf("cwd: %s\n", cwd);
return;
}
fclose(file);
}
int main(void) {
read_contents("/input_files/file_1.txt");
read_contents("/input_files/non-existing.txt");
}
и вот пример запуска:
Original path: /input_files/file_1.txt
Path after concatenating: ./input_files/file_1.txt
Original path: /input_files/non-existing.txt
Path after concatenating: ./input_files/non-existing.txt
Error: No such file or directory
cwd: /home/...
К сожалению, ваше решение не сработало. Я все еще получаю ту же ошибку, говорящую о том, что файл не может быть найден. Я дважды проверил структуру папок, имена файлов и операторы отладки, а также текущий рабочий каталог моего исполняемого файла, и все они кажутся правильными. Я не понимаю, почему это не работает.
Если вы получаете ту же ошибку, значит, вы не используете мою программу, поскольку она генерирует другой вывод.
Это также должно исправить проблему в принятом ответе (до того, как он был опубликован).
После прочтения всех возможных и распространенных решений в подобных случаях, которые не сработали в вашем случае, мое единственное предположение может заключаться в том, что в функцию передана искаженная C-строка, которая на первый взгляд может рассматриваться как правильная. Мне удалось воспроизвести аналогичную проблему на своем сайте, только передав в функцию read_contents некорректный указатель C-строки.
Главная идея. Допустим, у вас есть некоторый статически инициализированный массив в вашей основной функции, длина которого больше, чем длина пути к файлу. В моем воспроизведенном случае я взял массив байтов со 100 байтами в нем.
char path2[100] = {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x02};
также у меня есть
char path[] = "/file.txt" // strlen on this will result in 10 (includes \0)
После того, как я скопирую 9 байтов памяти в буфер пути2 из пути (исключая \0)
memcpy(path2, path, 9);
Обратите внимание, что я уже подготовил замену байта нулевого терминатора в path2 на байт 0x02 (это может быть любое мусорное значение)
После копирования памяти из правильного буфера в буфер path2. Результирующая строка также верна, и если мы ее распечатаем, мы увидим точно такую же строку, но последний байт перед нулевым терминатором равен 0x02, а не последний символ из начального пути.
Чтобы быть точным, буфер path2 будет выглядеть так после memcpy.
2F 66 69 6C 65 2E 74 78 74 02 00 .... 00
/ f i l e . t x t \0
вместо правильного
2F 66 69 6C 65 2E 74 78 74 00 .... 00
/ f i l e . t x t \0
При попытке распечатать эту строку вы даже не увидите пустого символа, как будто запасного байта не существует, но для системы это важно C:
При вызове предоставленной вами функции я получаю такой вывод
artyom@artyom:~/workspace/fopenfail$ ./a.out
Strlen /file.txt = 10
Original path: /file.txt
Path after concatenating: ./file.txt
Error: No such file or directory
artyom@artyom:~/workspace/fopenfail$ ls
a.out file.txt main.c
artyom@artyom:~/workspace/fopenfail$
Вот код, который я использовал в качестве возможного примера
void read_contents(char* file_path)
{
printf("\nOriginal path: %s\n", file_path);
// Trying to prefix the path with "." to indicate that the path is relative.
char prefix[1024] = ".";
strcat(prefix, file_path);
// Printing to make sure that prefix contains correct path.
printf("\nPath after concatenating: %s\n", prefix);
FILE* file = fopen(prefix, "r");
if (file == NULL)
{
perror("Error");
// Close the file and stop the function.
return;
}
// Code to read the file...
// ...
// Code to read the file...
fclose(file);
}
int main()
{
char path[] = "/file.txt";
char path2[100] = {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x02};
memcpy(path2, path, 9);
printf("Strlen %s = %d", path2, strlen(path2));
read_contents(path2);
return EXIT_SUCCESS;
}
Надеюсь, это послужит подсказкой, что не так в вызывающей функции.
Боже мой, большое спасибо. Я совсем забыл об этом.
Если вы пытаетесь выяснить, почему ваши файлы не найдены, всегда распечатывайте текущий рабочий каталог как часть ваших усилий по отладке.