Fopen() не может открыть файл

Я пытаюсь открыть файл и прочитать его содержимое. Но в настоящее время я просто пытаюсь открыть его.

Вот мой код:

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 находится текстовый файл.

Дополнительные вещи:

  1. Я запускаю правильный исполняемый файл с терминала.
  2. Путь правильный при переходе к функции.
  3. Структура и имена моих папок и файлов правильные.
  4. Разрешения правильные для доступа и чтения файлов.
  5. "." правильно добавляется в начало строки.

При всем этом я все еще получаю сообщение об ошибке, говорящее об отсутствии такого файла или каталога. Может ли кто-нибудь сказать мне, что мне не хватает?

Если вы пытаетесь выяснить, почему ваши файлы не найдены, всегда распечатывайте текущий рабочий каталог как часть ваших усилий по отладке.

President James K. Polk 26.06.2023 02:50

Зачем ты поставил точку впереди? Это полностью меняет смысл пути.

user207421 26.06.2023 03:23

Я добавил "." в начало строки, потому что я пытался выполнить то же самое без него, и я продолжал получать сообщение об ошибке. После некоторых исследований я обнаружил, что, по-видимому, если вы хотите обратиться к текущему каталогу, вам нужно сказать «./» (по крайней мере, в Linux). Вот почему я решил сделать это. Почему? Это неправильно? Если да, то подскажите как это сделать.

Default 26.06.2023 03:51

Похоже, что ваши настоящие каталоги и файлы имеют дополнительный префикс __. Если это часть имени, вам нужно включить его в строки пути.

Chris Dodd 26.06.2023 05:00

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

Default 26.06.2023 05:54

Если fopen() потерпел неудачу, вы не хотите fclose() этого. Пути, начинающиеся с /, являются абсолютными путями, все остальное относительно. Путь ./x` такой же, как просто x.

Allan Wind 26.06.2023 06:06

Отложите вашу программу в сторону. В том же терминале введите cat ./input_files/file_1.txt. Что вы наблюдаете?

n. m. will see y'all on Reddit 26.06.2023 07:09

Учитывая вашу настройку, программа должна работать, если выполняется с помощью «./executable». Если вы запустите его, скажем, "../executable", то он не будет работать.

linuxfan says Reinstate Monica 26.06.2023 07:57

Это действительно расстраивает, я полностью и полностью понимаю, что вы все предлагаете, и ценю это, но по какой-то причине это просто странно. Я даже попробовал предложение для этой команды: cat ./input_files/file_1.txt Когда я выполняю эту команду из терминала из точного местоположения моего исполняемого файла, это фактически дает мне правильные результаты: 10 20 30 В этот момент я потерял дар речи. Если я дам то же самое своей программе, то fopen() скажет, что не может найти файл.

Default 26.06.2023 08:19

Я проверял путь, расположение исполняемого файла, структуру файла, имена файлов, имена папок и операторы отладки, такие как getcwd(), printf и т. д., снова и снова (27 раз) сейчас и, ради любви ко мне, я не вижу любая разница. И все же команда работает, а fopen() нет. В этот момент я теряю клетки мозга.

Default 26.06.2023 08:20

просто догадываюсь, есть неправильно истолкованный алгоритм. ИДК, может быть, вы называете это дополнительными пробелами в конце строки или с '\ r', или что-то в этом роде

yvs2014 26.06.2023 09:30

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

n. m. will see y'all on Reddit 26.06.2023 13:20
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
12
80
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

К сожалению, ваше решение не сработало. Я все еще получаю ту же ошибку, говорящую о том, что файл не может быть найден. Я дважды проверил структуру папок, имена файлов и операторы отладки, а также текущий рабочий каталог моего исполняемого файла, и все они кажутся правильными. Я не понимаю, почему это не работает.

Default 26.06.2023 08:07

Если вы получаете ту же ошибку, значит, вы не используете мою программу, поскольку она генерирует другой вывод.

Allan Wind 26.06.2023 19:00

Это также должно исправить проблему в принятом ответе (до того, как он был опубликован).

Allan Wind 26.06.2023 19:14
Ответ принят как подходящий

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

Надеюсь, это послужит подсказкой, что не так в вызывающей функции.

Боже мой, большое спасибо. Я совсем забыл об этом.

Default 26.06.2023 18:47

Другие вопросы по теме