在 C 语言中对文件中包含数据的行进行计数

Counting data-containing lines from a file in C

提问人:Crashzen 提问时间:10/22/2023 最后编辑:Crashzen 更新时间:10/22/2023 访问量:98

问:

我是一名目前正在学习 C 的大学生,我需要创建一个函数来打开文件并计算包含数据的行数,然后返回值。我在尝试从文件中读取多行时遇到问题。

这就是我目前所拥有的。

注意:这些在另一个文件中定义

#define FNAME "sample_data.txt"
#define NAMELEN 30
#include <stdio.h>
#include <stdlib.h>
#include "utility.h"

int get_datafile_size(char file_name) 
{
    FILE* fp = fopen(FNAME, "r");
    int datalines = 0;

    while (!feof(fp))
    {
        char temp_str[NAMELEN];

        fgets(temp_str, NAMELEN - 1, fp);
        
        if (temp_str[0] != "#" && temp_str[0] != " ")
        {
            datalines++;
        }
    }
    
    fclose(fp);
    printf("<%d>", datalines);
    return datalines;
}

目前,该函数仅输出第一行中的字符数。

供参考的是有问题的文件:

# These records are in the form EMPLOYEE_NAME:EMPLOYEE_ID:EMPLOYEE_SALARY
# The following are administrators::
Eric Braun:174328:240378.94
Sunil Ahuja:285832:190415.87

# The following are staff members:
Joe Smith:132754:25018.14
Sally Jones:158113:32019.55
Janice P Oliver:185639:11458.32
Robert North:317543:85321.11
Janice J Oliver:298734:47166.76

# The following are student workers:
Davy Crockett:345216:5372.18
Billy Bones:239954:1141.66
Amanda Nice:398751:514.32
Tiny T Tim:301865:1093.54

函数输出:

<27>
C 文件

评论

5赞 Chris 10/22/2023
为什么 “while( !feof(file) )” 总是错的?
0赞 Mark Benningfield 10/22/2023
换行符 ('\n') 表示一行。您的代码没有处理该问题。
0赞 n. m. could be an AI 10/22/2023
我在尝试从文件中读取多行时遇到问题。你怎么知道从文件中读取了多少行?我在尝试从文件中读取多行时遇到问题。如果此函数不太可能这样做。请显示函数生成的输入文件和输出。
0赞 Oka 10/22/2023
参数的用途是什么?char file_name
0赞 Fe2O3 10/22/2023
查看数据文件中的第一行。看缓冲区的大小()... 将加载 -1 个字符(额外的 -1,因此有空间来满足 NUL 终止字符串的保证)。结果?第一行将分几个段进行处理,疯狂地甩掉计数......30fgets()30-1

答:

1赞 Fe2O3 10/22/2023 #1

代码中有很多问题!

int get_datafile_size(char file_name)
- 不适当的函数名称
- 未指示 C 字符串文件名
charchar *

FILE* fp = fopen(FNAME, "r");
-什么?FNAME

while (!feof(fp))
- 不要使用...只是不要!feof()

char temp_str[NAMELEN];NAMELEN = 30
- 最好使用令牌而不是幻数。限制缓冲区大小不好。

fgets(temp_str, NAMELEN - 1, fp);
- 假设是深思熟虑的。不用担心。 考虑到这一点,并保证将返回以 NUL 结尾的字符串。 只要向缓冲区提供正确的缓冲区大小,就不会溢出缓冲区。
- 缓冲区和令牌可以单独更改。最好使用,允许编译器使用缓冲区的最新大小。
-1'\0'fgets()fgets()sizeof temp_str

if (temp_str[0] != "#" && temp_str[0] != " ")
- 将单个字符与包含一个字符和一个终止 NUL 字符的字符串混合在一起。使用号,而不是双引号

printf("<%d>", datalines);
- 假设这是一个“打印调试语句。如果没有 ,则此输出可能不会在预期时通过缓冲区推送。
更好用:
'\n'fprintf( stderr, "datalines<%d>\n", datalines );


如果函数对文件中任何行的长度没有期望,那就更好了。这可以通过处理单个字符(来自流的缓冲输入)来处理,因此速度不会严重降低。

int cnt_datalines( char *file_name ) {
    FILE *fp = fopen( file_name, "r" );
    if( fp == NULL )
        return -1; // let caller handle the error

    int datalines = 0;
    int ch;
    for( int bgn = 1; ( ch = fgetc( fp ) ) != EOF; bgn = ch == '\n' )
        // Add 1 only when 1st char after newline is not hash, SP or newline
        datalines += ( bgn && ch != '\n' && ch != '#' && ch != ' ' );

    fclose(fp);

    fprintf( stderr, "datalines <%d>\n", datalines );

    return datalines;
}

flag 变量在开始和遇到任何时候都为 trueTrue 表示下一个字符将是一行的开头。bgn'\n'

评论

0赞 Crashzen 10/22/2023
我尝试实现您的代码,但我得到的输出是“数据线 <1>”。我理解你所做的大部分工作,但还不足以知道为什么它没有给出预期的输出。我正在寻找这个特定文件的输出将类似于“数据线 <11>”。
0赞 Fe2O3 10/22/2023
我承认这个答案的早期版本有错别字。请尝试使用此当前版本。我刚刚用您发布的示例数据进行了尝试,输出是正确的 11 行......
0赞 Fe2O3 10/22/2023
谢谢! 如果您对上述内容有具体问题,我很乐意尝试解释。:-)
1赞 Crashzen 10/22/2023
我想我在很大程度上理解你的所作所为。由于我还没有太多的编程经验,所以我需要一分钟才能理解。这也是我们第一次处理文件的读取和写入,所以我需要一些时间来了解正在发生的事情。另外,我真的很感谢你的回答,因为我的工作量已经困了几天了。
1赞 chux - Reinstate Monica 10/22/2023
@Fe2O3,UV用于处理许多问题,但在这里使用看起来很滥用。恕我直言,最好在迭代情况下使用。A 在这里更有意义。for()for()while()
0赞 chux - Reinstate Monica #2

由于代码正在寻找 a 后跟 a 以外的其他内容的出现,因此可以考虑直接对其进行编码。'\n''#'

int previous = '\n';
int ch;
while ((ch = fgetc(fp)) != EOF) {
  datalines += previous == '\n' && !isspace(ch) && ch != '#';
  previous = ch;
}