Ошибка fopen для переменной filepath - PullRequest
0 голосов
/ 13 октября 2019

Эта функция передает путь текстового файла (mapper_path), который содержит пути к другим текстовым файлам в каждой строке. Я должен открыть файл mapper_path.txt, а затем открыть и оценить каждый из путей в нем (пример в выходных данных). fopen успешно работает с файлом mapper_path, но не с теми путями, которые он содержит. В состоянии сбоя он печатает ТОЧНЫЙ путь, который я пытаюсь открыть. Я работаю в C на окнах и выполняю команды в подсистеме Ubuntu.

Как правильно прочитать и сохранить подпуть в переменной, чтобы открыть его?

РЕШЕНО по предложению Ричи!

int processText(char * mapper_path, tuple * letters[])
{
    char line[LINE_SIZE];
    char txt_path[MAX_PATH];

    FILE * mapper_fp = fopen(mapper_path, "r");
    if(!mapper_fp)
    {
       printf("Failed to open mapper path: %s \n", mapper_path);
       return -1;
    }
      //!!! PROBLEM IS HERE !!!
    while(fgets(txt_path, MAX_PATH, mapper_fp))
    {
       //remove newline character from end
       txt_path[strlen(txt_path)-1] = 0;

       //open each txt file path, return -1 if it fails
       FILE* fp = fopen(txt_path, "r");
       if(!fp)
       {
          printf("Failed to open file path:%s\n", txt_path);
          return -1;
       } 
       //...more unimportant code

отпечатков: не удалось открыть путь к файлу: /mnt/c/users/adam/documents/csci_4061/projects/blackbeards/testtext.txt Это точный путь к файлу, который я пытаюсь открыть.

1 Ответ

4 голосов
/ 13 октября 2019

Я подозреваю, что проблема связана с этим:

Я работаю в C над окнами и выполняю команды в подсистеме Ubuntu.

Предположительно, вы создалифайл mapper.txt, использующий инструменты Windows, поэтому у него есть окончания строки Windows. Тем не менее, я думаю, что подсистема Ubuntu не знает об окончаниях строк Windows, и поэтому, даже если вы открываете файл в режиме 'r', он не переводит CR-LF в один \n. Когда вы затем удаляете \n в конце ввода, вы все равно оставляете \r.

, который \r не будет виден при печати строки, поскольку все, что он делает, этопереместите курсор в начало строки, и следующий символьный вывод будет \n. Обычно хорошей идеей является окружение строк другим текстом при печати отладочных сообщений, поскольку это может дать вам представление о такой проблеме. Если бы вы использовали:

printf("Failed to open file path: '%s'\n", txt_path);

, возможно, вы видели ошибку:

'ailed to open filepath: '/mnt/c/users/adam/documents/csci_4061/projects/blackbeards/testtext.txt

Здесь намек на то, что в конце строки есть \r, этоперезапись первого символа сообщения завершающим апострофом.


Не совсем точно сказать, что fgets "добавляет \n символ в конец [прочитанной строки]". Точнее сказать, что этот символ не удаляется, если он присутствует. Вполне возможно, что в конце строки нет новой строки. Например, строка может быть последней строкой в ​​текстовом файле, которая не заканчивается символом новой строки. Или fgets мог быть прерван из-за достигнутого вами ограничения на количество символов, а не из-за поиска символа новой строки.

Так что вам, безусловно, лучше использовать интерфейс getline, который имеет два преимущества: (а) он выделяет память для самой строки, поэтому вам не нужно заранее угадывать максимальную длину, и (б) он точно сообщает вам, сколько символов он прочитал, поэтому вам не нужно считать их.

Используя эту информацию, вы можете затем удалить \n, который находится в конце строки, если он есть, и затем удалить предшествующий \r, если он есть:

char* line = NULL;
size_t n_line = 0;
for (;;) {
    ssize_t n_read = getline(&line, &n_line, mapper_fp);
    if (n_read < 0) break;  /* EOF or some kind of read error */
    if (n_read > 0 && line[n_read - 1] == '\n') 
        line[nread--] = 0;
    if (n_read > 0 && line[n_read - 1] == '\r') 
        line[nread--] = 0;
    if (nread == 0) continue;  /* blank line */
    /* Handle the line read */
 }
 if (ferr(mapper_fp))
    perror("Error reading mapper file");
 free(line);
...