文本文件可写,结构后有 1 个空行。
类似于:
1 111 1 Peter 22 22 2 John Lays 3 3 3 Anne Belgs
The struct is:
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个字符),在填充结构体数组之前还是之后更好?< br/>文件每一行的格式为:
xx xxx x aaaaaaaaaa(x=数字,a=字符)
例如,如果其中一行是
9 123 4 第一个值错误
停止读取文件(通知用户),因为该行应该是:
9 123 4 第一个值错误
(9 后缺少一个空格) - 或因为 NAME 超过 10 个字符。
最佳答案
你没有展示如何true
设置于while(true)
,但必须基于 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 == '\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;
}
无论哪种方式,您都将使用“此”输入文件产生相同的输出,例如
示例使用/输出
$ ./bin/readwblanks ~/tmpd/file
1 111 1 Peter
22 22 2 John Lays
3 3 3 Anne Belgs
关于c - 读取带有空行的文本文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56159936/