11

使用C,有没有办法只读取文件的最后一行而不循环它的全部内容?

问题是该文件包含数百万行,每行都包含一个整数(long long int)。文件本身可能非常大,我想甚至高达 1000mb。我确信最后一行不会超过 55 位,但也可能只有 2 位。使用任何类型的数据库都没有选择......我已经考虑过了。

也许这是一个愚蠢的问题,但来自 PHP 背景的我发现很难回答。我到处找,但没有找到干净的东西。

目前我正在使用:

if ((fd = fopen(filename, "r")) != NULL) // open file
{
    fseek(fd, 0, SEEK_SET); // make sure start from 0
    while(!feof(fd))
    {
        memset(buff, 0x00, buff_len); // clean buffer
        fscanf(fd, "%[^\n]\n", buff); // read file *prefer using fscanf
    }
    printf("Last Line :: %d\n", atoi(buff)); // for testing I'm using small integers
}

这样我循环文件的内容,一旦文件变得大于〜500k行,事情就会变慢......

先感谢您。格言

4

4 回答 4

7

只是fseekfileSize - 55向前阅读?

于 2012-12-09T19:02:34.000 回答
5

如果存在最大行长,请在 end 之前寻找该距离。读到最后,找到缓冲区中的最后一个行尾。

如果没有最大行长,猜一个合理的值,在最后读那么多,如果没有行尾,把你的猜测加倍,然后再试一次。

在你的情况下:

/* max length including newline */
static const long max_len = 55 + 1;
/* space for all of that plus a nul terminator */
char buf[max_len + 1];

/* now read that many bytes from the end of the file */
fseek(fd, -max_len, SEEK_END);
ssize_t len = read(fd, buf, max_len);

/* don't forget the nul terminator */
buf[len] = '\0';

/* and find the last newline character (there must be one, right?) */
char *last_newline = strrchr(buf, '\n');
char *last_line = last_newline+1;
于 2012-12-09T19:03:47.023 回答
3

打开"rb"以确保您正在阅读二进制文件。然后fseek(..., SEEK_END)从后面开始读取字节,直到找到第一行分隔符(如果您知道最大行长度为 55 个字符,请读取 55 个字符......)。

于 2012-12-09T19:03:09.523 回答
2

行。这一切都对我有用。我学到了一些新东西。立即读取了 41mb 大且行数 >500k 的文件的最后一行。感谢你们所有人,尤其是“无用”(喜欢你昵称的争议,顺便说一句)。我将在这里发布代码,希望将来的其他人可以从中受益:

只读取文件的最后一行:

该文件的结构方式是添加了一个新行,并且我确信任何行都比我的例子中的 55 个字符短:

file contents:
------------------------
2943728727
3129123555
3743778
412912777
43127787727
472977827

------------------------

注意附加的新行。

FILE *fd;                           // File pointer
char filename[] = "file.dat";       // file to read
static const long max_len = 55+ 1;  // define the max length of the line to read
char buff[max_len + 1];             // define the buffer and allocate the length

if ((fd = fopen(filename, "rb")) != NULL)  {      // open file. I omit error checks

    fseek(fd, -max_len, SEEK_END);            // set pointer to the end of file minus the length you need. Presumably there can be more than one new line caracter
    fread(buff, max_len-1, 1, fd);            // read the contents of the file starting from where fseek() positioned us
    fclose(fd);                               // close the file

    buff[max_len-1] = '\0';                   // close the string
    char *last_newline = strrchr(buff, '\n'); // find last occurrence of newlinw 
    char *last_line = last_newline+1;         // jump to it

    printf("captured: [%s]\n", last_line);    // captured: [472977827]
}

干杯!格言

于 2012-12-09T22:11:00.660 回答