使用fscanf逐行遍历文件

7

好的,我有一个文本文件database.txt。

每一行都是一个用户,格式如下:

"John Smith"| 4| 80.00| "123 Lollipop Lane"| "New Jersey"| "08080"  

当我尝试做以下操作时:

database = fopen(fileName,"r");
while(fscanf(database,"%[^\n]", buffer) != EOF) { 
    printf("ATTEMPT TO: Insert user %s\n\n", buffer); 
    if (insert_Customer(clients, create_Customer(buffer)) < 0) { 
        printf("\nERROR: Failed to insert and create customer %s\n", buffer); 
    }
    else printf("\nSUCCESS: Inserted Customer %s\n\n", buffer); 
} 

它对于第一行运行良好,将整个行发送到create_Customer(char * buffer)函数中。出于某种我不理解的原因,在此之后,它不断尝试发送“John Smith”,而不是继续下一行。我认为我的格式不正确,但我无法弄清楚如何实现我想要的目标,即逐行读取此文件并将每行传递到create_Customer函数中。

检查 fscanf 的返回代码,以获取第一次成功读取后读取的字符数。猜测可能返回 0,因为您告诉它读取除换行符以外的任何内容。 - Anya Shenanigans
4个回答

18

我认为你的模式中需要一个闭合的\n。 我看到一堆滚动文本,第一行相同,使用%[^\n],但是使用%[^\n]\n,我看到了预期的输出。

然而,如果文件中的行超过缓冲区的大小,你可能会遇到一个问题,即你的缓冲区没有足够的空间。结果可能会出现截断。

测试版本1:

代码

#include <stdio.h>


int main(int argc, char * argv[])
{
    FILE * database;
    char buffer[30];

    database = fopen("test.txt", "r");

    if (NULL == database)
    {
         perror("opening database");
         return (-1);
    }

    while (EOF != fscanf(database, "%[^\n]\n", buffer))
    {
         printf("> %s\n", buffer);
    }

    fclose(database);
    return (0);
}

结果

> 12343456567856789
> zbasdflkjasdfkjklsdafjklas
> zxcvjkleryjkldhfg
> 1234567890123456789012341234
> 12345678901234567890123123asdfjklzxcv;jkl;eqwrtjklkzlcxvjkleqrt41234
*** stack smashing detected ***: ./fscanf terminated                                                                                                                   
Segmentation fault (core dumped)

测试v2:

让我们修复代码以避免溢出缓冲区。这可以通过将%[^\n]\n更改为%30[^\n]\n来实现。这告诉 fscanf 它只能使用缓冲区的大小 - 30。

代码

#include <stdio.h>


int main(int argc, char * argv[])
{
    FILE * database;
    char buffer[30];

    database = fopen("test.txt", "r");

    if (NULL == database)
    {
         perror("opening database");
         return (-1);
    }

    while (EOF != fscanf(database, "%30[^\n]\n", buffer))
    {
         printf("> %s\n", buffer);
    }

    fclose(database);
    return (0);
}

结果

看起来它运行成功了!

> 12343456567856789
> zbasdflkjasdfkjklsdafjklas
> zxcvjkleryjkldhfg
> 1234567890123456789012341234
> 12345678901234567890123123asdf
> jklzxcv;jkl;eqwrtjklkzlcxvjkle
> qrt41234

test.txt

这就是我使用的测试文件的样子。

12343456567856789
zbasdflkjasdfkjklsdafjklas
zxcvjkleryjkldhfg
1234567890123456789012341234
12345678901234567890123123asdfjklzxcv;jkl;eqwrtjklkzlcxvjkleqrt41234

你为什么使用 fscanf 而不是 fgets

如果你使用 fgets,需要注意的一点是你可能需要去除字符串中的 \n 字符,因为它会作为字符串的一部分被包含进去。

cplusplus.com 的描述来看,fgets 的功能是:

从流中读取字符并将它们存储为 C 字符串到 str 中,直到读取了 (num-1) 个字符或者遇到换行符或文件结尾为止,以先到者为准。

示例:

/* fgets example */
#include <stdio.h>

int main()
{
    FILE * database;
    int res;
    char buffer [100];

    database = fopen(fileName,"r");

    if (NULL == database) {
        perror("opening database file");
        return (-1);
    }

    /* while not end-of-file */
    while (!feof(database)) { 

        /* we expect buffer pointer back if all is well, get out if we don't get it */
        if (buffer != fgets(buffer, 100, database))
            break;

        /* strip /n */
        int len = strlen(buffer);
        if (buffer[len - 1] == '\n')
            buffer[len - 1] = 0;

        printf("ATTEMPT TO: Insert user %s\n\n", buffer); 

        if (insert_Customer(clients, create_Customer(buffer)) < 0)
            printf("\nERROR: Failed to insert and create customer %s\n", buffer); 
        else
            printf("\nSUCCESS: Inserted Customer %s\n\n", buffer);
    }

    /* a little clean-up */
    fclose(database);

    return (0);
}

这些例子中有一个不是?哪一个? - rkyser

2
问题在于你的 fscanf 永远不会读取第一行末尾的换行符。所以当第二次调用时,它会失败(返回0而非EOF),什么也不读取,使得buffer 保持不变。
你可以在 while 循环结束处添加一个调用 fscanf("%*[\n]"); 的操作来跳过换行符(和可能出现的空白行)。或者你也可以使用 fgets,这也更容易避免潜在的缓冲区溢出问题。

1
你需要使用fgets,而不是fscanffscanf会读取到换行符\n为止,而使用相同的代码,你可以使用fgets来读取所有行!希望这有所帮助 :)

0

在指定符号“%[^\n]”后面加上一个空格或使用“%[^\n]\n”。两者都可以让你跳过换行符。

fscanf(database, "%[\n] ", buffer);

或者

fscanf(database, "%[\n]\n", buffer);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接