引言 - 问题的构建

   C大部分读取文件的时候采用fgetc, 最近在使用过程中发现性能不是很理想.都懂得fgetc每次只能读取一个字符, IO操作太频繁. 

所以性能低. 本文希望通过标准库函数fread 函数构建读取缓冲区来优化这个瓶颈

在正式开始实验总结之前, 传一个VS C/C++ 开发的技巧给大家, 天外飞仙~ .

  M$忽略C++太久了,对于C直接放弃, 在其Visual Studio IDE中. 但是吧在Window 还是它的IDE写C 系列语言最爽.

现在很流行一个低端套路是, Window VS 开发, Linux上部署. 而我们的问题就是关于这个, 这种不同平台的开发和部署,

存在一个坑就是编码问题. 而这里就是希望完美的解决这个编码问题.

  解决基准是选用UTF-8 带签名的编码, VS , GCC都能编译通过. 那就一言不合上图了, 首先定位VC模板文件

C基础 大文件读取通过标准库

将上面模板文件备份一份, 复制一份, 用VS打开复制的那份

C基础 大文件读取通过标准库

高级选项另存为上面编码格式. 最终保存替换原先的模板文件. 从此以后, 编码问题 perfect! 继续扯一点, 随着写代码时间增长, VS的依赖已经不重要的.

可惜喜欢打游戏, 还是被window 游戏机绑定了. 真的是离开I可以, 请付出代价~ /(ㄒoㄒ)/~~

 

前言 - 实验验证

  这里验证的是fgetc 和 fread读取性能的对比. 在说之前,  先介绍个测试宏

// 简单的time帮助宏
#ifndef TIME_PRINT
#define _STR_TIME_PRINT "The current code block running time:%lf seconds\n"
#define TIME_PRINT(code) \
    do {\
        clock_t __st, __et;\
        __st = clock();\
        code\
        __et = clock();\
        printf(_STR_TIME_PRINT, (0.0 + __et - __st) / CLOCKS_PER_SEC);\
    } while(0)
#endif // !TIME_PRINT

非常还用, 将代码块插入到 code中, 就可以使用了. 那继续了, 第一个测试的主体内容是, 实验一 fread对比fgetc

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

#define _STR_DATA    "data.txt"
#define _INT_DATA    (1024*1024*32)

// 测试 fgetc 性能
void test_fgetc(void);

// 测试 fread 性能
void test_fread(void);

//
// 测试C大文件处理方式
//
int main(int argc, char * argv[]) {

    // 先构建测试环境
    FILE * txt = fopen(_STR_DATA, "r");
    if (NULL == txt) {
        txt = fopen(_STR_DATA, "w");
        if (NULL == txt) {
            fprintf(stderr, "main fopen w " _STR_DATA " error!\n");
            exit(EXIT_FAILURE);
        }

        // 开始写入数据
        for (int i = 0; i < _INT_DATA; ++i)
            fprintf(txt, "%d", i);
    }
    fclose(txt);

    // 开始测试数据, 分批测试
    TIME_PRINT({
        test_fgetc();
    });

    TIME_PRINT({
        test_fread();
    });

    return 0;
}

其中两个测试函数如下.

//
// 测试 fgetc 性能
//
void 
test_fgetc(void) {
    FILE * txt = fopen(_STR_DATA, "r");
    if (NULL == txt) {
        fprintf(stderr, "test_fgetc fopen w " _STR_DATA " error!\n");
        return;
    }

    size_t cnt = 0;
    int c;

    while ((c = fgetc(txt)) != EOF)
        ++cnt;

    fclose(txt);

    printf("test_fgetc cnt = %d\n", cnt);
}

// 
// 测试 fread 性能
//
void test_fread(void) {
    FILE * txt = fopen(_STR_DATA, "r");
    if (NULL == txt) {
        fprintf(stderr, "test_fread fopen w " _STR_DATA " error!\n");
        return;
    }

    size_t cnt = 0;
    char buf[BUFSIZ];

    for (;;) {
        int rn = fread(buf, sizeof(char), BUFSIZ, txt);
        // 存在信号中断情况, 不考虑
        cnt += rn;
        if (rn < BUFSIZ)
            break;
    }

    fclose(txt);

    printf("test_fread cnt = %d\n", cnt);
}

测试主要思路是. 

  a. 构建差不多是200-300Mb的数据文件

  b. 通过fgetc 完毕, 输出时间

  c. 通过fread 完毕, 输出时间

测试结果如下

C基础 大文件读取通过标准库

我们发现, fread构建缓冲区有质的飞跃.

附录测试完整内容 file_test.c

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

#define _STR_DATA    "data.txt"
#define _INT_DATA    (1024*1024*32)

// 简单的time帮助宏
#ifndef TIME_PRINT
#define _STR_TIME_PRINT "The current code block running time:%lf seconds\n"
#define TIME_PRINT(code) \
    do {\
        clock_t __st, __et;\
        __st = clock();\
        code\
        __et = clock();\
        printf(_STR_TIME_PRINT, (0.0 + __et - __st) / CLOCKS_PER_SEC);\
    } while(0)
#endif // !TIME_PRINT

// 测试 fgetc 性能
void test_fgetc(void);

// 测试 fread 性能
void test_fread(void);

//
// 测试C大文件处理方式
//
int main(int argc, char * argv[]) {

    // 先构建测试环境
    FILE * txt = fopen(_STR_DATA, "r");
    if (NULL == txt) {
        txt = fopen(_STR_DATA, "w");
        if (NULL == txt) {
            fprintf(stderr, "main fopen w " _STR_DATA " error!\n");
            exit(EXIT_FAILURE);
        }

        // 开始写入数据
        for (int i = 0; i < _INT_DATA; ++i)
            fprintf(txt, "%d", i);
    }
    fclose(txt);

    // 开始测试数据, 分批测试
    TIME_PRINT({
        test_fgetc();
    });

    TIME_PRINT({
        test_fread();
    });

    return 0;
}

//
// 测试 fgetc 性能
//
void 
test_fgetc(void) {
    FILE * txt = fopen(_STR_DATA, "r");
    if (NULL == txt) {
        fprintf(stderr, "test_fgetc fopen w " _STR_DATA " error!\n");
        return;
    }

    size_t cnt = 0;
    int c;

    while ((c = fgetc(txt)) != EOF)
        ++cnt;

    fclose(txt);

    printf("test_fgetc cnt = %d\n", cnt);
}

// 
// 测试 fread 性能
//
void test_fread(void) {
    FILE * txt = fopen(_STR_DATA, "r");
    if (NULL == txt) {
        fprintf(stderr, "test_fread fopen w " _STR_DATA " error!\n");
        return;
    }

    size_t cnt = 0;
    char buf[BUFSIZ];

    for (;;) {
        int rn = fread(buf, sizeof(char), BUFSIZ, txt);
        // 存在信号中断情况, 不考虑
        cnt += rn;
        if (rn < BUFSIZ)
            break;
    }

    fclose(txt);

    printf("test_fread cnt = %d\n", cnt);
}
View Code

相关文章: