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

Bad*_*dda 8 c io file fgets file-processing

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

示例:

file.txt的

foo
fooo
fo
here
Run Code Online (Sandbox Code Playgroud)

通常,为了得到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;
}
Run Code Online (Sandbox Code Playgroud)

但是fgets必须完全阅读三行并且currentLine必须存储foo,fooo并且fo.

有没有更好的方法来做到这一点,知道here第4行?有点像go to文件?

gsa*_*ras 8

由于你不知道每一行的长度,,你将不得不通过前面的行.

如果你知道每一行的长度,你可以使用移动文件指针的字节数.你可以这样做fseek().


Bas*_*tch 5

您无法直接访问文本文件的给定行(除非所有行都具有相同的字节大小;并且对于UTF8, Unicode字符可以采用可变数量的字节,1到6;并且在大多数情况下,行具有各种长度 - 从一行到另一行不同).所以你不能使用fseek(因为你事先不知道文件偏移量).

但是(至少在Linux系统上),行以\n(换行符)结束.所以你可以逐字节读取并计算它们:

int c= EOF;
int linecount=1;
while ((c=fgetc(file)) != EOF) {
  if (c=='\n')
    linecount++;
}
Run Code Online (Sandbox Code Playgroud)

然后,您不需要存储整行.

因此,您可以通过这种方式到达第45行(使用while ((c=fgetc(file)) != EOF) && linecount<45)...),然后在POSIX系统上读取整行fgets或更好的getline(3)(参见示例).请注意,执行fgetsgetline很可能会再建fgetc,或至少与它分享一些代码.请记住,<stdio.h>缓冲的 I/O,见setvbuf用来(3)和相关的功能.


另一种方法是两遍读取文件.第一遍在一些有效的数据结构(向量,哈希表,树......)中存储每行开始的偏移量(使用ftell(3) ...).第二遍使用该数据结构来检索偏移量(行开始),然后使用fseek(3)(使用该偏移量).


第三种方式,POSIX特定,将使用mmap(2)将文件内存映射到您的虚拟地址空间(这适用于不太大的文件,例如小于几千兆字节).小心(您可能需要mmap一个额外的结束页面,以确保数据是零字节终止),然后您将能够使用strchr(3)'\n'

PS.顺便说一下,线的概念(和行尾标记)因操作系统而异.在Linux上,行尾是一个\n字符.据传,Windows上的线路以等结尾\r\n......


小智 5

FILE *C中的A 是chars 的流.在可搜索文件中,您可以char使用文件指针来解决这些问题fseek().但除此之外,文件中没有"特殊字符",换行符只是另一个普通字符.

所以总之,不,你不能直接跳到文本文件的一行,只要你事先不知道行的长度.

C中的此模型对应于典型操作系统提供的文件.如果你考虑一下,要知道各行的起点,你的文件系统就必须在某处存储这些信息.这意味着要特别处理文本文件.

然而你可以做的只是计算线而不是模式匹配,如下所示:

#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;
}
Run Code Online (Sandbox Code Playgroud)