【问题标题】:C: read only last line of a file. No loopsC:只读文件的最后一行。没有循环
【发布时间】:2012-12-09 19:00:46
【问题描述】:

使用 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行,事情就会变慢......

提前谢谢你。 格言

【问题讨论】:

标签: c file-io


【解决方案1】:

只需将fseek 转至fileSize - 55 并继续阅读?

【讨论】:

    【解决方案2】:

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

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

    在你的情况下:

    /* 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;
    

    【讨论】:

    • 好的,知道了。谢谢。 55 缓冲区中可能有多个“\n”,因为不能保证所有行都是 55 字符长,它们可以是 2 或 20,但不超过 55。所以至少有一个是肯定的。但这是我最小的问题。 fseek() 正是我想要的。谢谢!
    • 我收到一个错误:从 'FILE* {aka _iobuf*}' 到 'int' [-fpermissive] 的无效转换在线:ssize_t len = read(fd, buff, max_len);有没有想过我可能做错了什么?
    • 啊,改用size_t len = fread(buf, max_len, 1, fd):你有一个FILE*,但我写的好像你使用的是整数文件描述符(通常称为fd)。
    【解决方案3】:

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

    【讨论】:

    • 如果我理解正确,那么我从后面读了 55 个字符,然后一遇到 "\n",我就打破并反转所读的内容(因为它将是另一个我想是这样)。
    • 无需逐个字符读取...只需读取最后 56 个字符并找到最后一个换行符。
    【解决方案4】:

    好的。这一切都对我有用。我学到了一些新东西。立即读取了 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]
    }
    

    干杯! 格言

    【讨论】:

      猜你喜欢
      • 2019-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-08
      • 2021-06-23
      • 1970-01-01
      相关资源
      最近更新 更多