在 C 中逐行浏览文本文件
Posted
技术标签:
【中文标题】在 C 中逐行浏览文本文件【英文标题】:Going through a text file line by line in C 【发布时间】:2012-03-01 15:24:32 【问题描述】:我一直在为我的 CIS 课程做一个小练习,并且对 C 用于读取文件的方法感到非常困惑。我真正需要做的就是逐行读取文件,并使用从每一行收集的信息进行一些操作。我尝试使用 getline 方法和其他没有运气的方法。 我的代码目前如下:
int main(char *argc, char* argv[])
const char *filename = argv[0];
FILE *file = fopen(filename, "r");
char *line = NULL;
while(!feof(file))
sscanf(line, filename, "%s");
printf("%s\n", line);
return 1;
现在我遇到了 sscanf 方法的 seg 错误,我不知道为什么。我是一个总 C 菜鸟,只是想知道我是否遗漏了一些重要的事情。 谢谢
【问题讨论】:
这段代码甚至不应该编译。sscanf(line, filename, "%s");
应该是 sscanf(line, file, "%s");
请注意while (!feof(file))
is always wrong。
C read file line by line的可能重复
【参考方案1】:
这么几行就这么多问题。我可能忘记了一些:
argv[0]是程序名,不是第一个参数; 如果你想读入一个变量,你必须分配它的内存 一个永远不会在 feof 上循环,一个在 IO 函数上循环直到它失败,然后 feof 用于确定失败的原因, sscanf是用来解析一行的,如果你想解析一个文件,使用fscanf, “%s”将作为 ?scanf 系列的格式在第一个空格处停止 读取一行,标准函数是fgets, 从 main 返回 1 表示失败所以
#include <stdio.h>
int main(int argc, char* argv[])
char const* const fileName = argv[1]; /* should check that argc > 1 */
FILE* file = fopen(fileName, "r"); /* should check the result */
char line[256];
while (fgets(line, sizeof(line), file))
/* note that fgets don't strip the terminating \n, checking its
presence would allow to handle lines longer that sizeof(line) */
printf("%s", line);
/* may check feof here to make a difference between eof and io failure -- network
timeout for instance */
fclose(file);
return 0;
【讨论】:
在返回之前不要忘记fclose(file)
。
fclose(file)
实际上没有必要,因为它发生在main
中,它会自动关闭所有打开的文件缓冲区。
@Leandros 安全总比抱歉好!
对于初学者来说还是不错的,因为有时即使在 main 的末尾也是必要的。 FILE*
对象在 C 中缓冲,因此如果正在将数据写入文件并且未调用 fclose
,则某些数据可能不会被刷新。
嗨,@alecRN:你确定吗? AFAIK,当程序通过调用 exit 终止时,流上的缓冲输出会自动刷新(请参阅:gnu.org/software/libc/manual/html_node/Flushing-Buffers.html),并且操作系统将决定何时刷新(可以调用 fsync)。在执行结束时有一个对 exit_group 的隐式调用,您可以使用 strace 和 nm 看到它。我想它不是由 gcc 添加的,因为没有这样的符号,可能是运行时添加的。甚至 _exit 也会关闭打开的文件描述符。无论如何,我同意你的观点,明确关闭打开的文件是一个好习惯 /Ángel【参考方案2】:
要从文件中读取一行,您应该使用fgets
函数:它从指定文件中读取一个字符串,直到换行符或EOF
。
在您的代码中使用sscanf
根本不起作用,因为您使用filename
作为格式字符串,用于从line
读取到常量字符串文字%s
。
SEGV的原因是你写入了line
指向的未分配内存。
【讨论】:
【参考方案3】:除了其他答案之外,在最近的 C 库(符合 Posix 2008)上,您可以使用getline。请参阅this answer(相关问题)。
【讨论】:
【参考方案4】:假设您正在处理一些其他分隔符,例如 \t
制表符,而不是 \n
换行符。
一种更通用的分隔符方法是使用getc()
,它一次抓取一个字符。
请注意,getc()
返回一个int
,以便我们可以测试与EOF
是否相等。
其次,我们定义了一个char
类型的数组line[BUFFER_MAX_LENGTH]
,以便在堆栈上最多存储BUFFER_MAX_LENGTH-1
个字符(我们必须将最后一个字符保存为\0
终止符)。
使用数组避免了使用malloc
和free
在堆上创建正确长度的字符指针的需要。
#define BUFFER_MAX_LENGTH 1024
int main(int argc, char* argv[])
FILE *file = NULL;
char line[BUFFER_MAX_LENGTH];
int tempChar;
unsigned int tempCharIdx = 0U;
if (argc == 2)
file = fopen(argv[1], "r");
else
fprintf(stderr, "error: wrong number of arguments\n"
"usage: %s textfile\n", argv[0]);
return EXIT_FAILURE;
if (!file)
fprintf(stderr, "error: could not open textfile: %s\n", argv[1]);
return EXIT_FAILURE;
/* get a character from the file pointer */
while(tempChar = fgetc(file))
/* avoid buffer overflow error */
if (tempCharIdx == BUFFER_MAX_LENGTH)
fprintf(stderr, "error: line is too long. increase BUFFER_MAX_LENGTH.\n");
return EXIT_FAILURE;
/* test character value */
if (tempChar == EOF)
line[tempCharIdx] = '\0';
fprintf(stdout, "%s\n", line);
break;
else if (tempChar == '\n')
line[tempCharIdx] = '\0';
tempCharIdx = 0U;
fprintf(stdout, "%s\n", line);
continue;
else
line[tempCharIdx++] = (char)tempChar;
return EXIT_SUCCESS;
如果你必须使用char *
,那么你仍然可以使用这个代码,但是你strdup()
line[]
数组,一旦它被填满了一行的输入。完成后必须free
这个重复的字符串,否则会出现内存泄漏:
#define BUFFER_MAX_LENGTH 1024
int main(int argc, char* argv[])
FILE *file = NULL;
char line[BUFFER_MAX_LENGTH];
int tempChar;
unsigned int tempCharIdx = 0U;
char *dynamicLine = NULL;
if (argc == 2)
file = fopen(argv[1], "r");
else
fprintf(stderr, "error: wrong number of arguments\n"
"usage: %s textfile\n", argv[0]);
return EXIT_FAILURE;
if (!file)
fprintf(stderr, "error: could not open textfile: %s\n", argv[1]);
return EXIT_FAILURE;
while(tempChar = fgetc(file))
/* avoid buffer overflow error */
if (tempCharIdx == BUFFER_MAX_LENGTH)
fprintf(stderr, "error: line is too long. increase BUFFER_MAX_LENGTH.\n");
return EXIT_FAILURE;
/* test character value */
if (tempChar == EOF)
line[tempCharIdx] = '\0';
dynamicLine = strdup(line);
fprintf(stdout, "%s\n", dynamicLine);
free(dynamicLine);
dynamicLine = NULL;
break;
else if (tempChar == '\n')
line[tempCharIdx] = '\0';
tempCharIdx = 0U;
dynamicLine = strdup(line);
fprintf(stdout, "%s\n", dynamicLine);
free(dynamicLine);
dynamicLine = NULL;
continue;
else
line[tempCharIdx++] = (char)tempChar;
return EXIT_SUCCESS;
【讨论】:
我会对任何while(!feof(file))
投反对票,即使是在不可损坏的蓝月亮出现的情况下(请注意,这里可能永远不会是真的,有一个休息时间可以离开在这种情况下,循环 while (true)
也可以。)有太多人认为这是正确的习惯用法。
我不知道这是个问题。老实说,我很想了解更多有关这方面的信息。这种用法有什么问题?
出现了很多问题,例如***.com/questions/5431941/…。
好的,我修复了循环。感谢您的指点。我每天都能学到新东西。以上是关于在 C 中逐行浏览文本文件的主要内容,如果未能解决你的问题,请参考以下文章