我如何使用scanf读取文本文件中的下一行

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我如何使用scanf读取文本文件中的下一行相关的知识,希望对你有一定的参考价值。

我有一个分配,我需要使用scanf从文本文件中读取输入,并将输入临时存储到结构中,最后使用printf进行打印。我们不允许使用结构数组。

这是文本文件:

1010  Jose Manalo      3.5
2003  Luisa Santos     2.5
1008  Andres Espinosa  4.0

这里是给定的结构(String20是20个字符的数组):

struct nameTag {
    String20 first;
    String20 last;
};

struct studentTag {
    int ID;
    struct nameTag name;
    float grade;
};

我的初始代码如下(studentInfo是我的studentTag的结构变量):

scanf("%d %s %s %f", &studentInfo.ID, studentInfo.name.first, studentInfo.name.last, &studentInfo.grade);
printf("%d %s %s %.1f", studentInfo.ID, studentInfo.name.first, studentInfo.name.last, studentInfo.grade);

这当然只读取并打印第一行

编辑(已解决):将scanf放入一个循环中,直到达到EOF或NULL为止,效果很好。这是我所做的:

while(scanf("%d %s %s %f", &studentInfo.ID, studentInfo.name.first, studentInfo.name.last, &studentInfo.grade)!=NULL)
    printf("%d %s %s %.1f
", studentInfo.ID, studentInfo.name.first, studentInfo.name.last, studentInfo.grade);
答案

[scanf用于从stdin读取输入流,也就是说,您可以使用的最接近的函数是fscanf,类似于scanf,但是您可以指定要读取的文件:

#include <stdio.h>

typedef char String20[20];

struct nameTag {
    String20 first;
    String20 last;
};

struct studentTag {
    int ID;
    struct nameTag name;
    float grade;
};

int main()
{
   FILE* f;
   if(!(f = fopen("file.txt", "r"))) {
       return 1;
   }

   struct studentTag studentInfo; 

   while(fscanf(f, "%d %19s %19s %f", &studentInfo.ID, studentInfo.name.first, studentInfo.name.last, &studentInfo.grade) == 4)
        printf("%d %s %s %.1f
", studentInfo.ID, studentInfo.name.first, studentInfo.name.last, studentInfo.grade);
}

Live sample

使用fscanf的返回值来验证是否读取了正确的字段数并将其用作停止参数。

请注意,对于读取char数组,重要的是指定要读取的字符串的长度,例如,对于char[20]字符数组容器,可以使用"%s19"说明符,以避免堆栈粉碎。

另一答案

一次读取一行时,请使用面向行输入功能,例如fgets()或POSIX getline()。这避免了试图仅使用scanf()来从文件读取的新C程序员的许多陷阱。

[单独使用scanf()的问题很多,但是归结为尝试读取后输入流中剩下的内容。例如,当使用scanf()尝试读取整数值时,如果在数字之前遇到非数字,则会发生matching-failure,并且从输入流中停止字符提取,这将导致所有问题输入流中的字符未读-除非下次手动将字符从输入流中清空,否则请等待下一次尝试再次咬你。读取float作为最后一个值后,' '保留在输入流中未读取,并且如果下次读取时,您的格式说明符不忽略前导空白,则将空白视为您的输入。 (这只是冰山一角...)

因此,请使用fgets()一次将整行读取到适当大小的字符数组中。这样,您一次消耗了整条生产线。然后,您可以使用sscanf()从数据行中解析所需的内容。无论解析成功与否,您都不会影响从文件中读取下一行数据。数据读取和值解析不再在单个操作中耦合。

将各个部分放在一起,您可以执行以下操作:

#include <stdio.h>
#include <string.h>

#define MAXC  1024
#define MAXNM   20

typedef char String20[MAXNM];   /* your typedef */

struct nameTag {
    String20 first;
    String20 last;
};

struct studentTag {
    int ID;
    struct nameTag name;
    float grade;
};

int main (int argc, char **argv) {

    char buf[MAXC];     /* buffer to hold each line */
    size_t n = 0;       /* counter for number of students */
    struct studentTag std[MAXNM] = {{ .ID = 0 }};
    /* 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;
    }

    /* read each line -- until array full of EOF reached */
    while (n < MAXNM && fgets (buf, MAXC, fp)) {
        struct studentTag tmp = { .ID = 0 };    /* temporary struct to fill */
        if (sscanf (buf, "%d %19s %19s %f",     /* parse value from line */
                    &tmp.ID, tmp.name.first, tmp.name.last, &tmp.grade) == 4)
            std[n++] = tmp; /* assign temp struct to array on success */
        else    /* on error */
            fprintf (stderr, "error: line format - %s", buf);
    }
    if (fp != stdin)   /* close file if not stdin */
        fclose (fp);

    for (size_t i = 0; i < n; i++)  /* output all stored student data */
        printf ("
ID: %d
First: %s
Last: %s
Grade: %f
",
                std[i].ID, std[i].name.first, std[i].name.last, std[i].grade);

    return 0;
}

[note:您总是通过checking return来验证每个用户输入和值的解析,请参阅Henry Spencer's 10 Commandments for C Programmers - No. 6 “被警告...”

示例使用/输出

将数据放在dat/studenttag.txt中,您将提供文件名作为第一个参数并接收:

$ ./bin/readstudenttag dat/studenttag.txt

ID: 1010
First: Jose
Last: Manalo
Grade: 3.500000

ID: 2003
First: Luisa
Last: Santos
Grade: 2.500000

ID: 1008
First: Andres
Last: Espinosa
Grade: 4.000000

仔细检查,如果还有其他问题,请告诉我。

另一答案

最佳方法是使用fgets,然后按David在评论中建议的使用sscanf。Scanf是一种安全的方法,因为它可能导致缓冲区溢出。虽然,我认为您正在寻找这样的东西:

#include <stdio.h>

struct nameTag
{
  char first[20],last[20];
};

struct studentTag
{
  int ID;
  struct nameTag name;
  float grade;
};

int main(void)
{
  struct studentTag studentInfo;
  FILE *filein;
  filein=fopen("file.txt","r");
  while (!feof(filein)) /* Reading each line until EOF */
  {
   if (fscanf(filein,"%d %s %s %f",&studentInfo.ID, studentInfo.name.first, studentInfo.name.last, &studentInfo.grade)==0)
       ;
    printf("%d %s %s %.1f
", studentInfo.ID, studentInfo.name.first, studentInfo.name.last, studentInfo.grade);
  }
return 0;
}
另一答案

您可以使用fscanf

    fptr = fopen("c2.txt", "r+");
if(fptr!=Null)
    for (!feof(fptr))
    {
        fscanf(fptr,"%d %s %s %f
", &studentInfo.ID, studentInfo.name.first, studentInfo.name.last, &studentInfo.grade);
        printf("%d %s %s %.1f
", studentInfo.ID, studentInfo.name.first, studentInfo.name.last, studentInfo.grade);

    }

以上是关于我如何使用scanf读取文本文件中的下一行的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Pig 中读取 csv 文件中的下一行

C++ 使用条件语句读取文本文件

请问VB中如何读取txt文件的数据

Perl 中的简单文件读取

使用 POI 从 Excel 工作表中的下一行获取值

如何将长文本文件字段放入列表框?