在C中最快的fgets实现

时间:2018-07-07 08:20:54

标签: c performance implementation fgets libc

已知的fgets libc函数实现在内部使用了fgetc(),如何使用具有更大缓冲区或其他方法的read()来加速该函数?

例如,我阅读了/proc/pid/maps文件以搜索一些字符串。该文件的格式是已知的,当前我在fgets的链接中使用read(fd, &c, 1);实现,而不是getc。我认为从文件中读取单个字节比读取200个字节要慢。所以我想修改函数以从文件中读取N个字节,然后找到一个换行符。我认为替换1字节读取可以以某种方式加快功能。

2 个答案:

答案 0 :(得分:6)

您完全误解了标准I / O功能。甚至fgetc也被缓冲。使用read测试实际strace呼叫的发出。在我的计算机上,阅读/proc/1/maps

read(3, "5634f9cf6000-5634f9e44000 r-xp 0"..., 1024) = 1024
read(3, "                   /lib/x86_64-l"..., 1024) = 1024
read(3, "             /lib/x86_64-linux-g"..., 1024) = 1024
read(3, "                   /lib/x86_64-l"..., 1024) = 1024
read(3, ".0.0\n7feb2b2dc000-7feb2b4db000 -"..., 1024) = 1024
read(3, "0-7feb2b8e7000 r--p 00002000 fd:"..., 1024) = 1024
read(3, "00 rw-p 0001a000 fd:00 145004   "..., 1024) = 1024
read(3, "ux-gnu/liblzma.so.5.2.2\n7feb2c1b"..., 1024) = 1024
read(3, "6_64-linux-gnu/libgcrypt.so.20.2"..., 1024) = 1024
read(3, "000 fd:00 135558                "..., 1024) = 1024
read(3, "--p 0000e000 fd:00 136910       "..., 1024) = 1024
read(3, "001e000 fd:00 131385            "..., 1024) = 1024
read(3, "1.1.0\n7feb2da14000-7feb2da15000 "..., 1024) = 1024
read(3, "0 rw-p 00000000 00:00 0 \n7feb2de"..., 1024) = 1024
read(3, "-237.so\n7feb2e492000-7feb2e69100"..., 1024) = 1024
read(3, " \n7feb2ed15000-7feb2ed36000 rw-p"..., 1024) = 637
read(3, "", 1024)                       = 0

read调用尝试读取1024个字节,而不仅仅是一个字节。

程序是

#include <stdio.h>

int main(void) {
    FILE *f = fopen("/proc/1/maps", "r");
    while (1) {
        char buf[2048];
        if (! fgets(buf, 2048, f)) {
            break;
        }
    }
}

如果1024个字节不足以容纳您,则可以使用setvbuf(3)来更改基础缓冲区的大小!

答案 1 :(得分:1)

给您一个提示(但应修改为一次读取多个字节)

...我们拥有函数fgetsR(),它使用函数read()而不是fgetc()。在下面的代码中,有两个功能:

  • fgets0()是K&R fgets()函数
  • fgetsR()是一个fgets()函数,它使用read()而不是fgetc()

fgetsR函数主要用于读取文件(在命令行中指定)并显示其内容。

#include <unistd.h>

#include <stdlib.h>
#include <time.h>
#include <malloc.h>

char * fgets0(char *dst, int max, FILE *fp);
char * fgetsR(char *dst, int max, FILE *fp);

char * fgets0(char *dst, int max, FILE *fp)
{
    int c;
    char *p;

    /* get max bytes or upto a newline */

    for (p = dst, max--; max > 0; max--) {
        if ((c = fgetc (fp)) == EOF)
            break;
        *p++ = c;
        if (c == '\n')
            break;
    }
    *p = 0;
    if (p == dst || c == EOF)
        return NULL;
    return (p);
}

char * fgetsR(char *dst, int max, FILE *fp)
{
    int c;
    char *p,x;

    /* get max bytes or upto a newline */

    for (p = dst, max--; max > 0; max--) {
        if ((c = read(fileno(fp),&x,1)) == EOF || !c)
            break;
        *p++ = x;
        if (x == '\n')
            break;
    }
    *p = 0;
    if (p == dst || c == EOF || !c)
        return NULL;
    return (p);
}


int main(int argc, char *argv[])
{
    FILE * f = NULL;
    char buffer[1024];

    if (argc<2) {
        puts("You have to specify a file to read!");
        return 1;
    }

    f=fopen(argv[1],"r");

    while(fgetsR(buffer,sizeof(buffer),f)) {
        printf("%02X %s",*buffer,buffer);
    }

    fclose(f);

    return 0;
}

我不认为解决方案会更好,更快。上面的main()需要一些解决方法来控制发生错误时的流程。