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 是否成功、检查转换结果,并在使用后关闭流。