Чтение файла построчно, и при этом сохраняется только последняя строка в файле

#c #fgets

#c #fgets

Вопрос:

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

Нью-Йорк, 4:20,3:03
Канзас-Сити, 12:03,3:00
Северная бухта, 16:00,0:20
Завершение работы, 10:00,4:02
Тандер Бэй, 0:32,0:31

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

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

 #include <stdio.h>
#include <stdlib.h>
#include <string.h>

#pragma warning(disable: 4996)

// a function to remove the trailing carriage return
void clearTrailingCarraigeReturn(char *buffer);

/* == FUNCTION PROTOTYPES == */

/* == CONSTANTS == */
#define RECORD_SIZE     256
#define NUM_RECORDS     5
#define CHUNK_SIZE  1024    
#define STRING_SIZE 80

// MAIN
int main(int argc, char *argv[]) {
    FILE    *fp;
    char    flightInfo[RECORD_SIZE] = { 0 };
    char    cityName[20] = {};
    char    flightHour[20] = {};
    char    flightMin[20] = {};
    char    layoverHour[20] = {};
    char    layoverMin[20] = {};
    int     i = 0;

    struct flightInfo {
        char flightName[20];
        double flightTime;
        double layoverTime;
    };

    fp = fopen(argv[1], "r");
    // first - we'll check the command-line arguments to ensure that the user specified 
    // a single argument - which we will assume is the name of a file
    if (argc != 2) {
        printf("Sorry - you need to specify the name of a file on the command line.n");
        return -1;
    }

    if (fp == NULL) {
        printf("Can't open the TEXT file for readingn");
        return -4;
    }

    // get each of the lines from the file
    while (fgets(flightInfo, sizeof flightInfo, fp) > 0) {
        clearTrailingCarraigeReturn(flightInfo);
        // display the line we got from the file
        printf("  >>> read record [%s]n", flightInfo);
    }

    // we exited the reading loop - was it because we read the EOF?
    if (feof(fp)) {
        printf(" [DONE reading the file ... we've reached the EOF]n");
    } else {
        // we exited the loop because of an error
        if (ferror(fp)) {
            // there's an error
            printf("Error reading a record from the filen");
            if (fclose(fp) != 0) {
                // we can't even close the file
                printf("Can't close the TEXT file we opened for readingn");
            }
            return -5;
        }
    }
}

// This function locates any carriage return that exists in a record
// and removes it ...
void clearTrailingCarraigeReturn(char *buffer) {
    char *whereCR = strchr(buffer, 'n');
    if (whereCR != NULL) {
        *whereCR = '';
    }
}
  

Ответ №1:

В вашем коде множество проблем:

  • вы должны проверить, присутствует ли аргумент командной строки перед попыткой открыть файл.
  • тест для вашего цикла чтения неверен: fgets() возвращает указатель на целевой массив or NULL , поэтому вам следует использовать не > 0 , а это вместо:

     while (fgets(flightInfo, sizeof flightInfo, fp) != 0)
      
  • символ 'n' называется новой строкой, а не возвратом каретки. На устаревших платформах, n преобразуется в 2 байта в текстовых файлах 0D 0A , т.е.: возврат каретки и перевод строки.

  • цикл считывает содержимое файла, но не анализирует содержимое строки и не сохраняет его в переменные, которые вы определили для этого. Вы должны проанализировать строку, преобразовать значения и сохранить информацию в следующей записи в flighInfo структурном массиве:

         if (sscanf(flightInfo, "[^,],%2[0-9]:%2[0-9],%2[0-9]:%2[0-9]",
                   cityName, flightHour, flightMin, layoverHour, layoverMin) == 5) {
            /* convert the times into `double` values and store the info */
        } else {
            /* report the error, exit */
        }
      
  • вы используете одно и то же имя для struct flightInfo тега и char массива. Это сбивает с толку и чревато ошибками. Вам следует переименовать char массив line или buf .

  • вы должны закрыть файл во всех случаях.

Ответ №2:

Вы не сохраняете результаты сканирования. Эти строки:

 while (fgets(flightInfo, sizeof flightInfo, fp)  > 0)
{

    clearTrailingCarraigeReturn(flightInfo);
    // display the line we got from the file
    printf("  >>> read record [%s]n", flightInfo);
}
  

Считывает следующую строку в flightInfo (которая является массивом char ), и когда появляется следующая строка, ее перечитывают в начало flightInfo заново. Самая последняя прочитанная строка будет сохранена в flightInfo.

Вам также нужно сохранить эту строку, если вы хотите сохранить ее. НАПРИМЕР, вы могли бы сделать что-то вроде:

 char multiple_flight_info[100][1024];
int i = 0;
while (fgets(multiple_flight_info[i], 1024, fp)  > 0)
{
    clearTrailingCarraigeReturn(flightInfo[i]);
    // display the line we got from the file
    printf("  >>> read record [%s]n", flightInfo);
    i  ;
    if (i > 100) { exit(1); } /* do better error exiting here */
}
  

По сути, это создает двойной массив. Первый индекс — это номер считываемой строки, а второй индекс — это позиция символа в прочитанной строке.

Для обеспечения «безопасности» необходимо сделать гораздо больше, а не читать отдельные строки, потому что одна из них слишком длинная, и т.д. Но это может помочь вам начать.

Комментарии:

1. while (fgets(multiple_flight_info[i], 1024, fp) > 0) должно быть while (fgets(multiple_flight_info[i], 1024, fp) != NULL)