HOWTO · C

在 C 语言中使用 fscanf 逐行读取文件

本文演示了如何在 C 语言中使用 fscanf 逐行读取文件。

本页内容

fscanf 从 FILE 流中读取格式化输入。扫描集可以读取直到换行符之前的字符,但与专用的逐行读取函数不同,使用它时需要明确处理空行和有界的数据块。对于普通文本文件,fgets 通常更简单;当输入格式需要转换时,再使用 fscanf。

在 C 中使用 fscanf 逐行读取文件

这个完整示例会创建临时文件、写入两行示例文本,再使用扫描集读取流;读取宽度受 16 字节的目标缓冲区限制。程序把两行示例文本写入临时流,并在读取时逐行打印。代码和输出中的示例文字保持英文。

#include <stdio.h>

int main(void) {
    FILE *file = tmpfile();
    char line[16];

    if (file == NULL) {
        return 1;
    }
    if (fputs("First line.\nSecond line.\n", file) == EOF || ferror(file)) {
        fclose(file);
        return 1;
    }
    if (fflush(file) == EOF || ferror(file)) {
        fclose(file);
        return 1;
    }
    rewind(file);

    for (;;) {
        int result = fscanf(file, "%15[^\n]", line);
        if (result == 1) {
            int ch;
            puts(line);
            ch = fgetc(file);
            if (ch == '\n') {
                continue;
            }
            if (ch == EOF) {
                break;
            }
            ungetc(ch, file);
            while ((ch = fgetc(file)) != '\n' && ch != EOF) {
            }
            if (ch == EOF) {
                break;
            }
            continue;
        }
        if (result == EOF) {
            break;
        }
        if (fgetc(file) == '\n') {
            puts("");
        }
    }

    fclose(file);
    return 0;
}

宽度设为 15,可为 line 中的终止空字符留出空间。每次扫描集转换成功后,程序都会检查换行符。如果一行内容超出缓冲区,它会在读取下一行前丢弃剩余部分;这样可以限制内存用量,但不会完整保留超长行。若扫描集在换行符处没有匹配到任何字符,循环会消耗该换行符并打印一个空行,而不会在没有进展的情况下重试。生产代码还应在输入结束后检查 ferror(file),以区分读取错误和正常的文件结束。

使用 fscanf 读取以空白字符分隔的词元

解析词元时,%255s 会将一个非空白词元读入 char token[256] 缓冲区。宽度限制可防止写入超出数组范围;%s 会跳过前导空白字符,并在下一个空白字符处停止。循环应仅在 fscanf(file, "%255s", token) == 1 时继续;如果转换失败且没有消耗输入,只检查 EOF 可能导致循环永远重复。此方法会有意将空格、制表符和换行符都视为分隔符,因此无法保留原始行界。读取数字字段时,应使用匹配的转换说明符,并检查成功赋值的数量。

使用 fgets 可靠地逐行读取

如果文本中的每条记录都是一行,fgets(buffer, sizeof buffer, file) 通常更容易理解。它最多读取缓冲区容量减一的字符;如果换行符能放入缓冲区,也会一并保留。使用缓冲区之前,先检查函数的返回值。如果缓冲区已满但没有读到换行符,逻辑上的这一行仍有后续内容留在流中;应根据任务需要继续读取后续数据块,或丢弃剩余部分。文件最后一行可能在没有换行符的情况下到达 EOF。fgets 也能自然处理空行,因为它可能返回只包含换行符的缓冲区。

需要读取格式化字段或以空白字符分隔的词元时,选择 fscanf。需要保留行界时,选择 fgets,然后视需要单独解析读取到的字符串。始终检查 fopen 是否成功、检查转换结果,并在使用后关闭流。