好的,所以在阅读了How to read a specific line in a text file in C (integers)和What is the easiest way to count the newlines in an ASCII file?之后,我认为我可以使用两者中提到的点来高效快速地从文件中读取一行
这是我的代码:
char buf[BUFSIZ];
intmax_t lines = 2; // when set to zero, reads two extra lines.
FILE *fp = fopen(filename, "r");
while ((fscanf(fp, "%*[^\n]"), fscanf(fp, "%*c")) != EOF)
{
/* globals.lines_to_feed__queue is the line that we _do_ want to print,
that is we want to ignore all lines up to that point:
feeding them into "nothingness" */
if (lines == globals.lines_to_feed__queue)
{
fgets(buf, sizeof buf, fp);
}
++lines;
}
fprintf(stdout, "%s", buf);
fclose(fp);
现在上面的代码运行得非常好,而且我非常高兴对我自己感到满意,因为我知道你可以fscanf
一个文件到某一点,然后使用{ {1}}将所述点上的数据读入缓冲区,而不是每行fgets
然后fgets
buf,当我关心的是我所在的行时;打印:我不想在缓冲区中存储我可能不太关心的字符串,而我只会在一行中使用一次。
然而,正如fprintf
评论所指出的那样,我遇到了唯一的问题:// when set to zero, reads two extra lines
初始化时的值为lines
,以及我想要的行就像0
一样,我得到的行实际上就是行200
。有人可以解释一下我在这里做错了什么/为什么会发生这种情况以及我的快速解决方案 202
是否正常或是否不足(如果是,这是真的错了)继续在这里,只是 发生 才能工作?)
答案 0 :(得分:3)
您必须将lines
设置为2
有两个原因,并且两者都可以从您想要第一行的特殊情况派生。
一方面,在while
循环中,您要做的第一件事是使用fscanf
来使用一行,然后检查lines
计数器是否与您想要的行匹配。问题是,如果您想要的线路是您刚刚消耗的线路,那么您运气不好。另一方面,你基本上通过查找下一个\n
并在之后递增lines
来检查当前行是否是你所追求的行。
这两个因素组合导致lines
计数的偏移,因此以下是将它们考虑在内的同一函数的版本。此外,一旦到达您要查找的行,它还包含break;
语句,以便while
循环停止查看文件。
void read_and_print_line(char * filename, int line) {
char buf[BUFFERSIZE];
int lines = 0;
FILE *fp = fopen(filename, "r");
do
{
if (++lines == line) {
fgets(buf, sizeof buf, fp);
break;
}
}while((fscanf(fp, "%*[^\n]"), fscanf(fp, "%*c")) != EOF);
if(lines == line)
printf("%s", buf);
fclose(fp);
}
答案 1 :(得分:1)
正如另一种查看问题的方式......假设您的全局在第一行打印时指定1
,第二行打印2
等,则:
char buf[BUFSIZ];
FILE *fp = fopen(filename, "r");
if (fp == 0)
return; // Error exit — report error.
for (int lineno = 1; lineno < globals.lines_to_feed_queue; lineno++)
{
fscanf(fp, "%*[^\n]");
if (fscanf(fp, "%*c") == EOF)
break;
}
if (fgets(buf, sizeof(buf), fp) != 0)
fprintf(stdout, "%s", buf);
else
…requested line not present in file…
fclose(fp);
你可以用fclose(fp);
和return;
代替中断,如果合适的话(但请确保在退出之前关闭文件;否则,你会泄漏资源)。
如果您的行号从0开始计算,则将for
循环的下限更改为0
。
答案 2 :(得分:0)
首先,关于这里的错误:此代码无法读取文件中的第一行(如果globals.lines_to_feed__queue
为0,会发生什么?)。如果文件包含连续的换行符,它也会错误计算行数。
其次,你必须意识到没有魔力。由于您不知道相关字符串所处的偏移量,因此您必须耐心地逐个字符地读取文件,并沿途计算字符串结尾。如果您将阅读/计数委托给fgets
/ fscanf
或fgetc
每个字符进行人工检查,那么无关紧要 - 无论哪种方式,一个无趣的文件都会成功从磁盘进入OS缓冲区,然后进入用户空间进行解释。
你的直觉是绝对正确的:代码被打破了。