【问题标题】:How to use fgets to read a file line by line如何使用 fgets 逐行读取文件
【发布时间】:2017-01-27 20:26:28
【问题描述】:

我是编程新手,所以有一些我不知道的基础知识和常识。我有一个关于如何正确使用 fgets 的问题。根据对 fgets 的解释,似乎 fgets 应该在读取 n-1 个字符、命中 EOF 或命中换行符时停止。 例如,我创建如下文本文件:

red  100
yellow  400
blue  300
green 500
purple 1000
...

颜色和整数由制表符分隔。当我创建这个文本文件时,我需要在每一行的末尾按回车键来开始新的一行。在这种情况下,按回车等于添加换行符'\n',对吗?

如果每行末尾有一个'\n'是正确的,我运行fgets代码如下:

fgets(string, 100, fp);

由于每行包含的字符远小于 100,因此 fgets 应该在达到最大长度限制之前遇到换行符,并且应该停止并返回 NULL。对吗?

如果我上面的理解不对,每行的末尾没有'\n',或者fgets没有在每一行的末尾停止,那么maxlength的个数是多少(即, fgets(string, N, stream) function) 我应该选择确保文件输入正确,因为我的最终目标是解析每一行并将每一行存储到一个结构中。顺便说一下,文件有100行。

【问题讨论】:

  • 您的问题不清楚。您是什么意思“生成 .txt 文件”?展示一些示例代码,将那段文本分解成可读的段落,让我们更容易理解它。尽可能简洁地询问。
  • 您应该为nfgets 中选择的数字是缓冲区的字节长度。如果在文件中的 EOL 之前达到该限制,则输入字符串的末尾将没有 newline,并且对 fgets 的下一次调用将从文件中的同一位置继续。但这个问题是一个混乱。输出不是输入。
  • @cpatricio C 有 字符串。它们是末尾带有空字符的字符序列。
  • "如果我不知道每行包含多少个字符,我应该为 n 选择什么数字?" --> 在某种程度上,健壮的代码需要评估它是否被黑客入侵。如果代码没有限制,那么对my_favorite_input_function() 的调用允许外部代理占用系统资源。选择一个大的n - 建议两倍于程序需要的建议大小:#define LINE_SIZE 1000 或 80 或 8675309,并将 (strlen(buffer) >== LINE_SIZE - 1) 为真的任何输入视为恶意并以失败退出。
  • 这篇文章至少有 5 个范围很广的问题。建议缩小范围并发布您尝试过的内容。

标签: c file fgets c-strings


【解决方案1】:
 #include <stdio.h>

 int main()
 {
    char str[150],str2[100][150];
    int i=0,j=0,value[100];
    FILE* fp;
    fp = fopen("file.txt", "r");
    while (fgets(str,150, fp)) {
        i++;
        printf("%3d: %s\n", i, str);
        /** if you want to split value and string*/
        sscanf(str,"%s %d",&str2[j],&value[j]);
        printf("%d %s\n",value[j],str2[j]);
        j++;
    }
    fclose(fp);
    return 0;
}

您可以使用sscanf() 轻松拆分值,使用fgets() 读取文件。

【讨论】:

    【解决方案2】:
    fp = fopen("sample.txt", "r");
    while (1) {
            if (fgets(line,150, fp) == NULL) break;
            i++;
            printf("%3d: %s", i, line);
    }
    printf("%d\n",i);
    

    【讨论】:

    • 不应该是while(!feof(fp))还是while(fgets(..))?我一直认为尽可能避免使用breakcontinue 这样的声明是一个好习惯。
    • @ClaudioCortese 应该是后者。请看Why is “while ( !feof (file) )” always wrong?
    • 贴出line的定义,让fgets(line,150, fp)更清晰。
    • @chux 应该澄清什么?很明显line是一个大小为150的c字符串
    • @ClaudioCortese OP 是“编程新手”,因此发表了这篇文章。 OP 可能没有意识到数组大小的要求,偏离了一个,或者可能认为指针可以。或其他。发布一个显示正确用法的解决方案可以澄清答案,因为许多事情对于 C 新手来说并不明显。
    【解决方案3】:
    // hello.c
    //
    // Usage:
    //
    // gcc -Wall hello.c && ./a.out /tmp/somefile.txt
    
    #include <stdlib.h>     // for perror, ...
    #include <stdio.h>      // for printf, ...
    #include <assert.h>     // for assert
    #include <sys/time.h>   // for gettimeofday
    
    static inline long long int nowUs () {
      long long int now;
      struct timeval timer_us;
      if (gettimeofday(&timer_us, NULL) == 0) {
        now = ((long long int) timer_us.tv_sec) * 1000000ll +
          (long long int) timer_us.tv_usec;
      }
      else now = -1ll;
    
      return now;
    }
    
    int main (const int argc, const char * argv[]) {
      assert(2 == argc);
      long long int started = nowUs();
      size_t count = 0;
      char msg[128], * fgets_rv;
      FILE * fp = fopen(argv[1], "r");
    
      while ((fgets_rv = fgets(msg, sizeof(msg), fp))) {
        assert(fgets_rv == msg);
        count++;
      }
      if (ferror(fp)) 
        perror(argv[1]);
      else if (feof(fp)) {
        printf("Read %zu lines of file '%s' in %lldµs\n", 
            count, argv[1], nowUs() - started);
      }
      else {
        printf("UNEXPECTED\n");
      }
      fclose(fp);
      return 0;
    }
    

    样本输出:

    alec@mba ~/process/sandbox $ gcc -Wall hello.c && ./a.out /tmp/bigfile.t02
    Read 100000 lines of file '/tmp/bigfile.t02' in 16521µs
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-09-13
      • 2019-05-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多