Читать текстовый файл с пустыми строками - PullRequest
0 голосов
/ 16 мая 2019

Текстовый файл был доступен для записи с 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 \n\n", carro.id, carro.potencia, carro.avariado, carro.name);

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

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

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

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

Ответы [ 2 ]

1 голос
/ 16 мая 2019

Вы не показываете, как true установлено в while(true), но оно должно основываться на возврате 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 == '\n')           /* if line empty */
            continue;               /* get next line */
        if (sscanf (buf, "%d %d %d %10[^\n]",   /* 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\n",
            carro[i].id, carro[i].potencia, carro[i].avariado, carro[i].name);

    return 0;
}

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

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

    for (;;) {
        carro_t tmp = { .id = 0 };
        if (fscanf (fp, "%d %d %d %10[^\n]",    /* 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
0 голосов
/ 16 мая 2019

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

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

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

...