该文本文件可写,其结构后有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;
}
如何在不读取空白行的情况下读取文本文件并保存数据结构?
如果我想验证值(ID = xx,potencia = xxx,avariado = x,name = 10个字符),在填充struct数组之前还是之后更好? br />文件的每一行的格式为:
xx xxx x aaaaaaaaaa(x =数字,a =字符)
例如,如果其中一行是
9 123 4 Error 1st value
停止读取文件(通知用户),因为该行应为:
9 123 4 Error 1st value
(9后缺少一个空格)-或由于NAME的字符超过10个。
答案 0 :(得分:1)
您没有显示如何在true
中设置while(true)
,但是它必须基于您接近fscanf
的返回值。您必须测试三种情况:
fscanf
返回为EOF
,已读完成,true
应该设置为FALSE
才能中断循环; fscanf
返回少于4
, matching 或 input 失败,不能保证由于空行而发生;和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;
}
(注意:文件名作为程序的第一个参数提供,或者,如果未提供文件名,则默认从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;
}
无论哪种方式,您都将使用“ this”输入文件产生相同的输出,例如
使用/输出示例
$ ./bin/readwblanks ~/tmpd/file
1 111 1 Peter
22 22 2 John Lays
3 3 3 Anne Belgs
答案 1 :(得分:0)
只用简单的阅读方式就可以了,
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);
结果是这样的 enter image description here