|
|
俊逸的牛腩 · 医学三维图像几种格式的区别_vtp和vtu文 ...· 1 年前 · |
|
|
含蓄的电影票 · sourceTree在其他分支只合并某次提交 ...· 1 年前 · |
|
|
慷慨的抽屉 · phpcurl ...· 2 年前 · |
|
|
小胡子的李子 · python执行cmd命令获取执行程序返回的 ...· 2 年前 · |
|
|
温文尔雅的烤面包 · CSS Modules 用法教程 - ...· 2 年前 · |
比如说,我有一个文本文件
person1
person2
person3
..
不管有多少人,我想把文件的4行读成一个结构,供文件中的每个人使用。
我该怎么做?我尝试过使用多个fget,但是我不知道如何循环到文件的末尾,同时每次读取四行。
谢谢
发布于 2020-06-11 18:52:16
继续上面的注释,当您需要将数据文件中的固定重复行集读入
struct
时,这是唯一的例外,您应该考虑
scanf()/fscanf()
而不是建议的每一行的
fgets()/sscanf()
。
为什么?
scanf()
是一个格式化的输入函数(与面向行的输入函数
fgets()
相比)。如果您有跨多行的格式化输入,
scanf()/fscanf()
将忽略空格(
'\n'
字符为空白),并允许您将多行作为单个输入(使用精心编制的格式字符串)。
当使用
scanf()/fscanf()
将数据读入字符串(或数组)时,必须使用字段宽度修饰符来限制读取到数组中的值的数量,以避免在输入超过数组界限时调用未定义行为的数组末尾写入。每当您使用
scanf()/fscanf()/sscanf()
(整个家族)时,这都适用。使用没有字段宽度修饰符来读取数组数据并不比使用
gets()
更好。
那么如何制作您的格式字符串呢?让我们看一个包含4个成员的示例结构,类似于您在问题中所显示的内容。
...
#define MAXG 8 /* if you need a constant, #define one (or more) */
#define MAXP 32
#define MAXN 128
typedef struct { /* struct with typedef */
char name[MAXN], gender[MAXG];
int iq, weight;
} person;
...
如果您的数据如图所示,
name
声明为
128
字符,
gender
声明为
8
字符,其余两个成员为
int
类型,则可以执行以下类似操作:
int rtn; /* fscanf return */
size_t n = 0; /* number of struct filled */
person ppl[MAXP] = {{ .name = "" }}; /* array of person */
while (n < MAXP && /* protect struct array bound, and each array bound below */
(rtn = fscanf (fp, " %127[^\n]%d%d %7[^\n]", /* validate each read */
ppl[n].name, &ppl[n].iq, &ppl[n].weight, ppl[n].gender)) == 4)
n++; /* increment array index */
具体查看格式字符串时,您有:
" %127[^\n]%d%d %7[^\n]"
如果
" %127[^\n]"
凭借前导
' '
使用任何前导空格,然后最多读取
127
字符(不能使用变量或宏来指定字段宽度),则字符是行中任何不是
'\n'
字符的字符(允许将空白作为名称的一部分读取,例如
"Mickey Mouse"
)。
注意,
"%[...]
是一个字符串转换,它将将字符列表中的任何字符
[...]
作为字符串读取。使用
'^'
作为列表的第一个字符将导致
"%[^\n]"
将不包括
'\n'
的所有字符读取到字符串中。
" %[^\n]"
之前的空格是必需的,因为
"%[...]"
(如
"%c"
)是唯一不使用前导空格的转换说明符,因此您可以在格式字符串中的转换之前包含一个空格来提供这一点。另外两个用于
int
的转换说明符(例如,
"%d"
)将自己占用前导空格,从而导致总转换:
" %127[^\n]%d%d %7[^\n]"
总之,这将:
%127[^\n]
;
weight
左转到
iq
>d55(这消耗了whitespace);
weight
和
%d
(ditto);
' '
使用
weight
左的
'\n'
;最后,
%7[^\n]
(根据需要调整以保持最长的性别字符串)
将最多7个字符的一行读入
gender
成员中。
使用这种方法,您可以使用数组中每个结构的4行输入,只需调用一次
fscanf()
。您应该检查
rtn
on循环出口,以确保在读取文件中的所有值后,循环在
EOF
上退出。一个简单的检查将涵盖所需的最小验证。
if (rtn != EOF) /* if loop exited on other than EOF, issue warning */
fputs ("warning: error in file format or array full.\n", stderr);
(
注意:
,您也可以检查
n == MAXP
,以查看循环退出的原因是否是由于单独的数组已满)。
总之,你可以这样做:
#include <stdio.h>
#define MAXG 8 /* if you need a constant, #define one (or more) */
#define MAXP 32
#define MAXN 128
typedef struct { /* struct with typedef */
char name[MAXN], gender[MAXG];
int iq, weight;
} person;
int main (int argc, char **argv) {
int rtn; /* fscanf return */
size_t n = 0; /* number of struct filled */
person ppl[MAXP] = {{ .name = "" }}; /* array of person */
/* 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 (n < MAXP && /* protect struct array bound, and each array bound below */
(rtn = fscanf (fp, " %127[^\n]%d%d %7[^\n]", /* validate each read */
ppl[n].name, &ppl[n].iq, &ppl[n].weight, ppl[n].gender)) == 4)
n++; /* increment array index */
if (rtn != EOF) /* if loop exited on other than EOF, issue warning */
fputs ("warning: error in file format or array full.\n", stderr);
for (size_t i = 0; i < n; i++) /* output results */
printf ("\nname : %s\niq : %d\nweight : %d\ngender : %s\n",
ppl[i].name, ppl[i].iq, ppl[i].weight, ppl[i].gender);
if (fp != stdin) /* close file if not stdin */
fclose (fp);
}
(
注意:
您也可以使用全局
enum
来定义常量)
示例输入文件
$ cat dat/ppl.txt
person1
person2
female
Mickey Mouse
Minnie Mouse
female
示例使用/输出
$ ./bin/readppl dat/ppl.txt
name : person1
iq : 25
weight : 500
gender : male
name : person2
iq : 128
weight : 128
gender : female
name : Mickey Mouse
iq : 56
weight : 2
gender : male
name : Minnie Mouse
iq : 96
weight : 1
gender : female
您也可以使用行计数器或多行读取方法使用
fgets()
读取每一行,但这更多地是关于选择合适的工作工具。使用
fgets()
,然后对整数值多次调用
sscanf()
,或者对
strtol()
进行两个调用以进行转换没有什么问题,但是对于大输入文件,对
fscanf()
的1-函数调用与对
fgets()
+2的4次单独调用相比--对
sscanf()
或
strtol()
的单独调用--再加上处理线路计数器或多缓冲区逻辑的附加逻辑,将开始增加。
仔细考虑一下,如果你还有其他问题,请告诉我。
发布于 2020-06-11 17:32:49
一些例子行。剩下的部分我就交给你了。
#define MAX 1000
FILE *f;
char line1[MAX], line2[MAX], line3[MAX], line4[MAX];
while(fgets(line1, MAX, f) != NULL)
if (fgets(line2, MAX, f) == NULL ||
fgets(line3, MAX, f) == NULL ||
fgets(line4, MAX, f) == NULL)
/* insert code here to handle end of file in unexpected place */