c - 用 C 更快地读取文件

标签 c file scanf performance

嗯,我想知道是否有一种比使用 fscanf() 更快地读取文件的方法

例如假设我有这个文本

4

55 k

52 o

24 l

523 i

首先我想读取第一个数字,它给出了接下来的行数。

让这个数称为N。

在N之后,我想读取N行,其中有一个整数和一个字符。 使用fscanf,它会像这样

fscanf(fin,"%d %c",&a,&c);

最佳答案

您几乎不进行任何处理,因此瓶颈可能是文件系统吞吐量。但是,您应该先测量一下是否确实如此。如果您不想使用分析器,您可以只测量应用程序的运行时间。输入文件的大小除以运行时间可用于检查是否已达到文件系统吞吐量限制。

然后,如果您远离上述限制,您可能需要优化读取文件的方式。最好使用 fread() 以较大的 block 读取它,然后使用 sscanf() 处理存储在内存中的缓冲区。

您还可以自己解析缓冲区,这比 *scanf() 更快。​​

[编辑]

特别是对于德拉科沙:

$ time ./main1
Good entries: 10000000

real    0m3.732s
user    0m3.531s
sys 0m0.109s
$ time ./main2
Good entries: 10000000

real    0m0.605s
user    0m0.496s
sys 0m0.094s

所以优化版本的速度约为 127MB/s,这可能是我的文件系统的瓶颈,或者操作系统可能将文件缓存在 RAM 中。原始版本约为 20MB/s。

使用 80MB 文件进行测试:

10000000

1234 a

1234 a
...

ma​​in1.c

#include <stdio.h>

int ok = 0;
void processEntry(int a, char c) {
    if (a == 1234 && c == 'a') {
        ++ok;
    }
}

int main(int argc, char **argv) {
    FILE *f = fopen("data.txt", "r");
    int total = 0;
    int a;
    char c;
    int i = 0;

    fscanf(f, "%d", &total);
    for (i = 0; i < total; ++i) {
        if (2 != fscanf(f, "%d %c", &a, &c)) {
            fclose(f);
            return 1;
        }
        processEntry(a, c);
    }
    fclose(f);
    printf("Good entries: %d\n", ok);
    return (ok == total) ? 0 : 1;
}

ma​​in2.c

#include <stdio.h>
#include <stdlib.h>

int ok = 0;
void processEntry(int a, char c) {
    if (a == 1234 && c == 'a') {
        ++ok;
    }
}

int main(int argc, char **argv) {
    FILE *f = fopen("data.txt", "r");
    int total = 0;
    int a;
    char c;
    int i = 0;
    char *numberPtr = NULL;
    char buf[2048];
    size_t toProcess = sizeof(buf);
    int state = 0;
    int fileLength, lengthLeft;

    fseek(f, 0, SEEK_END);
    fileLength = ftell(f);
    fseek(f, 0, SEEK_SET);

    fscanf(f, "%d", &total);  // read the first line

    lengthLeft = fileLength - ftell(f);

    // read other lines using FSM
    do {
        if (lengthLeft < sizeof(buf)) {
            fread(buf, lengthLeft, 1, f);
            toProcess = lengthLeft;
        } else {
            fread(buf, sizeof(buf), 1, f);
            toProcess = sizeof(buf);
        }
        lengthLeft -= toProcess;
        for (i = 0; i < toProcess; ++i) {
            switch (state) {
                case 0:
                    if (isdigit(buf[i])) {
                        state = 1;
                        a = buf[i] - '0';
                    }
                    break;
                case 1:
                    if (isdigit(buf[i])) {
                        a = a * 10 + buf[i] - '0';
                    } else {
                        state = 2;
                    }
                    break;
                case 2:
                    if (isalpha(buf[i])) {
                        state = 0;
                        c = buf[i];
                        processEntry(a, c);
                    }
                    break;
            }
        }
    } while (toProcess == sizeof(buf));

    fclose(f);
    printf("Good entries: %d\n", ok);
    return (ok == total) ? 0 : 1;
}

关于c - 用 C 更快地读取文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4851381/

相关文章:

c - 奇怪的 C fprintf 格式符号

c - 空的初始值设定项列表是有效的 C 代码吗?

c - 为什么人们将自己的文件夹添加到标准包含路径?

c - K&R C while 循环省略大括号

java - 如何在 tomcat web 应用程序中锁定文件?

file - 在 opennlp 中训练自己的模型

c - sscanf 不动,每次扫描相同的整数

c - 此代码中的第二个 scanf 将不会读取。 (C 代码)

python - 在 Python 中写入文件时如何写入新行?

c - 如何避免在这个程序中输出前打印空行?