C:到已知的文件行的最佳方法



我有一个文件,我想在其中迭代而不以任何形式处理当前行。我正在寻找的是进入文本文件的确定行的最佳方法。例如,将当前行存储到变量中似乎是没有用的,直到我到达预定的行。

示例:

file.txt

foo
fooo
fo
here

通常,为了获得here,我会做类似的事情:

FILE* file = fopen("file.txt", "r");
if (file == NULL)
    perror("Error when opening file ");
char currentLine[100];
while(fgets(currentLine, 100, file))
{
    if(strstr(currentLine, "here") != NULL)
         return currentLine;
}

但是fgets必须无用地读取三行,并且currentLine必须存储foofooofo

知道here是第4行,有更好的方法可以做到这一点吗?类似于go to,但是用于文件吗?

由于您不知道每行的长度, no ,您将必须浏览以前的行。

如果您知道每行的长度,则可能会使用多少个字节来移动文件指针。您可以使用fseek()做到这一点。

您无法直接访问文本文件的给定行(除非所有行在 bytes ;中都具有相同的大小;可变数量的字节,1至6;在大多数情况下,线的长度各不相同 - 从一行到下一行都不同(。因此,您不能使用fseek(因为您不提前知道文件偏移(。

但是(至少在Linux系统上(,线以n(Newline字符(结尾。因此,您可以通过字节读取字节并计算它们:

int c= EOF;
int linecount=1;
while ((c=fgetc(file)) != EOF) {
  if (c=='n')
    linecount++;
}

您就不需要存储整个行。

因此,您可以以这种方式到达第45行(使用while ((c=fgetc(file)) != EOF) && linecount<45) ...(,然后在POSIX Systems上使用fgets或更好的GetLine(3(读取整个行(请参阅此示例(。请注意,fgetsgetline的实现可能位于fgetc上方,或者至少与之共享一些代码。请记住, <stdio.h>缓冲 i/o,请参阅setVbuf(3(和相关功能。


另一种方法是在两次通行证中读取文件。第一通通过以某些有效的数据结构(一个矢量,一个标签,树...(启动每行的偏移(使用ftell(3(...(。第二通过使用该数据结构来检索偏移(线启动的偏移(,然后使用fseek(3((使用该偏移(。


特定于POSIX的第三种方法是使用MMAP(2(进入您的虚拟地址空间(这对不太巨大的文件,例如少于几GB(。谨慎(您可能需要mmap一个额外的结尾页面,以确保数据终止为零(,然后您可以将STRCHR(3(与'n'

一起使用

在某些情况下,您可以考虑按行解析文本文件(使用适当的fgets或-ON Linux- getline,或使用Flex和Bison生成解析器(,然后将每行存储在关系数据库中(例如PostgreSQL或sqlite(。

ps。顺便说一句,线(和线路结束标记(的概念从一个操作系统到另一个OS不等。在Linux上,末端是n字符。有传言说在Windows线上以rn的结尾等...

C中的FILE *char s的流。在可寻求的文件中,您可以使用带有fseek()的文件指针来解决这些char s。但是除此之外,文件中没有"特殊字符",newline只是另一个普通字符。

简而

C中的该模型对应于典型操作系统提供的文件。如果您考虑一下,要知道单个线路的起点,则文件系统将必须在某个地方存储此信息。这意味着要专门处理文本文件。

您的 can 做的只是计数行而不是图案匹配,类似的是:

#include <stdio.h>
int main(void)
{
    char linebuf[1024];
    FILE *input = fopen("seekline.c", "r");
    int lineno = 0;
    char *line;
    while (line = fgets(linebuf, 1024, input))
    {
        ++lineno;
        if (lineno == 4)
        {
            fputs("4: ", stdout);
            fputs(line, stdout);
            break;
        }
    }
    fclose(input);
    return 0;
}

如果您不知道每行的长度,则必须遍历所有行。但是,如果您知道要停止的行,可以做到这一点:

while (!found && fgets(line, sizeof line, file) != NULL) /* read a line */
{
    if (count == lineNumber)
    {
         //you arrived at the line
         //in case of a return first close the file with "fclose(file);"
         found = true;
    }
    else
    {
        count++;
    }
}

至少您可以避免对strstr

的电话如此多的电话

最新更新