Текстовый файл был доступен для записи с 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
вы к нему приближаетесь. Вы должны проверить три случая:
fscanf
- EOF
, чтение выполнено, true
должно быть установлено в FALSE
для разрыва цикла; fscanf
возвращает меньше 4
, совпадение или ошибка ввода , нет гарантии, что это произошло из-за пустой строки; а также 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);
результат, как это введите описание изображения здесь