从C中的文件中读取特定行

时间:2014-04-13 03:53:52

标签: c file-io fgets scanf

好的,所以在阅读了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 是否正常或是否不足(如果是,这是真的错了)继续在这里,只是 发生 才能工作?)

3 个答案:

答案 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 / fscanffgetc每个字符进行人工检查,那么无关紧要 - 无论哪种方式,一个无趣的文件都会成功从磁盘进入OS缓冲区,然后进入用户空间进行解释。

你的直觉是绝对正确的:代码被打破了。