Читать текстовый файл с пустыми строками

Текстовый файл был доступен для записи с 1 пустой строкой после структуры.
Похож на:

1  111 1 Peter

22 22  2 John Lays

3  3   3 Anne Belgs

Структура является:

struct estruturaCarro {
    int id, potencia, avariado;
    char name[11]; 
} carro;

Я должен записать данные в текстовый файл:

fprintf(fp, "%-2d %-3d %-1d %-10s 

", carro.id, carro.potencia, carro.avariado, carro.name);

Я читаю данные файла таким образом, но я уверен, что это не лучший способ:

while(true){
    int result = fscanf(fp, "%d %d %d %10[^
]", &carro.id, &carro.potencia, &carro.avariado, &carro.name);
    if(result==4){    
            printf("%-2d %-3d %-1d % -s
", carro.id, carro.potencia, carro.avariado, carro.name);
    }else break;
}

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

Если я хочу проверить прочитанные значения (ID = xx, enercia = xxx, avariado = x, name = 10 символов), лучше ли это, до или после заполнения массива struct?
Формат каждой строки файла:
xx xxx x aaaaaaaaaa (x = цифры, a = символы)
Например, если одна из строк
9 123 4 Error 1st value
прекратить чтение файла (информирование пользователя), потому что строка должна быть:
9 123 4 Error 1st value (один пробел пропущен после 9) - или потому что NAME содержит более 10 символов.

Всего 2 ответа


Вы не показываете, как true установлено в while(true) , но оно должно основываться на возврате fscanf в том виде, в fscanf вы к нему приближаетесь. Вы должны проверить три случая:

  1. Возвращение fscanf - EOF , чтение выполнено, true должно быть установлено в FALSE для разрыва цикла;
  2. fscanf возвращает меньше 4 , совпадение или ошибка ввода , нет гарантии, что это произошло из-за пустой строки; а также
  3. fscanf равен 4 , хороший ввод.

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

Вот почему лучший вариант - прочитать каждую строку в буфер с помощью fgets а затем проанализировать необходимую информацию из самого буфера с помощью sscanf . Это обеспечивает преимущество отдельной проверки (1) чтения; и (2) анализ информации. Кроме того, поскольку вы используете строку за раз, нет никакой неопределенности в отношении того, что остается во входном потоке, и сбой при анализе любой одной строки не препятствует успешному чтению оставшейся части.

Короткая реализация с fgets() и sscanf() считывающая каждую структуру в массив структуры, вы можете сделать что-то похожее на следующее:

#include <stdio.h>

#define MAXN   11   /* if you need a constant, #define one (or more) */
#define MAXC 1024   /*         (don't skimp on buffer size)          */

typedef struct {    /* use a simple typedef */
    int id, potencia, avariado;
    char name[MAXN]; 
} carro_t;

int main (int argc, char **argv) {

    char buf[MAXC];                         /* buffer to read line */
    carro_t carro[MAXN] = {{ .id = 0 }};    /* array of struct  */
    size_t ndx = 0;                         /* array index      */
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

    while (ndx < MAXN && fgets (buf, MAXC, fp)) {   /* read each line */
        carro_t tmp = { .id = 0 };                  /* temp struct */
        if (*buf == '
')           /* if line empty */
            continue;               /* get next line */
        if (sscanf (buf, "%d %d %d %10[^
]",   /* separate/validate */
                    &tmp.id, &tmp.potencia, &tmp.avariado, tmp.name) == 4)
            carro[ndx++] = tmp;     /* add to array of struct */
    }
    if (fp != stdin) fclose (fp);   /* close file if not stdin */

    for (size_t i = 0; i < ndx; i++)
        printf ("%3d  %3d  %3d  %s
",
            carro[i].id, carro[i].potencia, carro[i].avariado, carro[i].name);

    return 0;
}

( примечание: имя файла указывается в качестве первого аргумента программы или, если имя файла не указано, по умолчанию считывается из stdin )

Хотя с вашим конкретным файлом данных нет причин, по которым вы не можете использовать fscanf , он хрупок, и слишком много символов (например, "Anne Belgss" ) приведут к его поломке. Реализация fscanf true и просто зацикливающаяся, как вы могли бы быть:

    for (;;) {
        carro_t tmp = { .id = 0 };
        if (fscanf (fp, "%d %d %d %10[^
]",    /* separate/validate */
                    &tmp.id, &tmp.potencia, &tmp.avariado, tmp.name) == 4)
            carro[ndx++] = tmp;     /* add to array of struct */
        else
            break;
    }

В любом случае, вы получите тот же вывод с «этим» входным файлом, например

Пример использования / Вывод

$ ./bin/readwblanks ~/tmpd/file
  1  111    1  Peter
 22   22    2  John Lays
  3    3    3  Anne Belgs

просто используйте простой способ чтения в порядке, как это.

  while(fscanf(fp,"%d %d %d %s",&carro.id,&carro.potencia,&carro.avariado,carro.name)!=EOF) printf("%d %d %d %s
",carro.id,carro.potencia,carro.avariado,carro.name); 

результат, как это введите описание изображения здесь


Есть идеи?

10000