分批读取文件中数据的程序流程及其C代码实现

简介: 分批读取文件中数据的程序流程及其C代码实现

一、概述

在实际的软件开发项目中,经常需要处理大量的文件。某些文件中包含了相当多的数据记录数,如作者本人参与过的项目中,一个文件中有好几十万条记录。如果一次性将多条记录读入,则会花费大量的处理时间,且占用大量的内存。为此,要求对于包含大量数据记录的文件进行分批读取操作,即每一轮读取一定数目的数据记录,待将这些记录处理完成之后,再读取下一批数据。本文介绍分批读取文件中数据的程序流程,并给出了C程序实现。

二、总体程序流程

实现分批读取文件中数据的程序流程如图1所示。

640.jpg

图1 实现分批读取文件中数据的程序流程

三、C程序实现

本程序命名为BatchReadFile.c,具体代码如下:

/**********************************************************************
* 版权所有 (C)2015, Zhou Zhaoxiong。
*
* 文件名称:BatchReadFile.c
* 文件标识:无
* 内容摘要:分批读取文件中的数据并打印出来
* 其它说明:无
* 当前版本:V1.0
* 作    者:Zhou Zhaoxiong
* 完成日期:20150528
*
**********************************************************************/
#include <stdio.h>
// 重定义数据类型
typedef signed   int    INT32;
typedef unsigned int    UINT32;
typedef unsigned char   UINT8;
// 宏定义
#define ONCE_READ_COUNT    5      // 一次读取的最大数据条数
#define MAX_RECORD_LEN     50     // 每条数据的最大长度
// 函数声明
INT32 ReadRecordFromFile(FILE *fp, UINT8 szRecordSet[][MAX_RECORD_LEN], UINT32 *piReadCnt);
INT32 main();
/**********************************************************************
* 功能描述:主函数
* 输入参数:无
* 输出参数:无
* 返 回 值:无
* 其它说明:无
* 修改日期        版本号         修改人           修改内容
* -------------------------------------------------------------------
* 20150528        V1.0     Zhou Zhaoxiong        创建
***********************************************************************/
INT32 main()
{
    UINT8  szFileName[256] = {0};     // 包含完整路径的文件名
    FILE  *fp              = NULL;    // 文件句柄
    UINT32 iReadCnt        = 0;       // 一次读取到的记录数
    UINT32 iRecCnt         = 0;       // 记录数, 循环变量
    UINT32 iReadTimes      = 0;       // 读取文件次数
    INT32  iRetVal         = 0;       // 读取文件函数的返回值
    UINT8  szRecordSet[ONCE_READ_COUNT][MAX_RECORD_LEN] = {0};   // 存放从文件中读取到的记录内容集
    UINT8  szRecordInfo[MAX_RECORD_LEN]                 = {0};   // 存放从文件中读取到的每条记录内容
    // 获取包含完整路径的文件名
    strcpy(szFileName, "/home/zxin10/zhouzx/test/file/TestFile.txt");
    // 打开文件
    fp = fopen(szFileName, "r");
    if (NULL == fp)   // 打开失败
    {
        printf("Open file %s failed!\n", szFileName);
        return -1;
    }
    // 读取文件内容并打印出来
    while (1)
    {
        iReadCnt = 0;
        memset(szRecordSet, 0x00, sizeof(szRecordSet));
        iRetVal = ReadRecordFromFile(fp, szRecordSet, &iReadCnt);
        if (iRetVal == -1)   // 表示函数执行失败, 直接退出
        {
            printf("Exec ReadRecordFromFile failed, please check!\n");
            break;
        }
        if (iReadCnt > 0)
        {
            iReadTimes ++;     // 读取次数加1
            printf("ReadTimes is: %d, the RecordInfo is:\n", iReadTimes);
        }
        for (iRecCnt = 0; iRecCnt < iReadCnt; iRecCnt ++)   // 打印读取到的记录值
        {
            memset(szRecordInfo, 0x00, sizeof(szRecordInfo));
            strncpy(szRecordInfo, szRecordSet[iRecCnt], sizeof(szRecordInfo)-1);
            printf("%s\n", szRecordInfo);
        }
        if (iRetVal == 0)   // 表示文件记录已扫描完, 直接退出
        {
            break;
        }
    }
    return 0;
}
/**********************************************************************
* 功能描述:从文件中读取记录内容
* 输入参数:fp-文件指针
* 输出参数:szRecordSet-记录内容信息集
            piReadCnt-读取到的条数
* 返 回 值:1-下一轮继续读取  0-本轮已读取完毕  -1-读取失败
* 其它说明:无
* 修改日期        版本号         修改人           修改内容
* -------------------------------------------------------------------
* 20150528        V1.0     Zhou Zhaoxiong        创建
***********************************************************************/
INT32 ReadRecordFromFile(FILE *fp, UINT8 szRecordSet[][MAX_RECORD_LEN], UINT32 *piReadCnt)
{
    UINT8  szRecordInfo[MAX_RECORD_LEN] = {0};    // 存储读取到的每条记录信息
    UINT32 iRecordLen                   = 0;      // 存储读取到的每条记录信息的长度
    if (fp == NULL || piReadCnt == NULL)
    {
        printf("ReadRecordFromFile: input paramter(s) is NULL!\n");
        return -1;
    }
    // 读取文件记录
    while ((!feof(fp)) && (!ferror(fp)))   // 遇到文件结尾或读取错误则退出
    {
        // 读取一条记录
        memset(szRecordInfo, 0x00, sizeof(szRecordInfo));
        fgets(szRecordInfo, sizeof(szRecordInfo)-1, fp);
        // 去掉记录后面的回车换行符
        iRecordLen = strlen(szRecordInfo);
        while (iRecordLen > 0)
        {
            if (szRecordInfo[iRecordLen-1] == '\n' || szRecordInfo[iRecordLen-1] == '\r')
            {
                szRecordInfo[iRecordLen-1] = '\0';
            }
            else
            {
                break;
            }
            iRecordLen --;
        }
        // 判断是否为空行, 是则继续读取
        if (strlen(szRecordInfo) == 0)
        {
            continue;
        }
        // 将记录信息拷贝到输出缓存中
        strncpy(szRecordSet[(*piReadCnt)++], szRecordInfo, MAX_RECORD_LEN-1);
        // 如果超出最大条数限制, 则直接返回
        if ((*piReadCnt) >= ONCE_READ_COUNT)
        {
            return 1;
        }
    }
    return 0;
}

四、程序说明

1.被读取的文件命名为“TestFile.txt”,存放在“/home/zhou/zhouzx/test/file/”目录下。


2.为了方便看到效果,程序中设定每一次最大读取条数为5,每条记录的最大长度为50(最大长度值的设定的依据是读取的文件记录的长度)。将读取到的记录存放到一个二维数组变量中,其中第一维是每次读取到的记录条数,第二维是每条记录的长度。


3.如果一轮未读完数据,则文件指针会自动跳到下一次读取的记录的开头。结束一轮读取的条件有三个:已达读取上限、记录已全部读完、读取错误。


4.如果文件中出现了空行,那么程序并不会将之作为有效行而使得读取条数增加,而是从下一个非空行开始继续计数。


5.程序会打印出读取的次数及每次读取到的具体记录信息,方便查看程序分批处理的执行情况。

五、程序编译及运行结果

在Linux下,使用“gcc -g -o BatchReadFile BatchReadFile.c”命令对程序进行编译,生成“BatchReadFile”。下面执行“BatchReadFile”命令来对程序进行测试。


1.“TestFile.txt”文件中的内容如下:

100001
100002
100003
100004

则程序运行结果为:

ReadTimes is: 1, the RecordInfo is:
100001
100002
100003
100004

2.“TestFile.txt”文件中的内容如下:

100001
100002
100003
100004
100005

则程序运行结果为:

ReadTimes is: 1, the RecordInfo is:
100001
100002
100003
100004
100005

3.“TestFile.txt”文件中的内容如下:

100001
100002
100003
100004
100005
100006

则程序运行结果为:

ReadTimes is: 1, the RecordInfo is:
100001
100002
100003
100004
100005
ReadTimes is: 2, the RecordInfo is:
100006

4.“TestFile.txt”文件中的内容如下:

100001
100002
100003
100004
100005
100006
100007
100008
100009
100010
100011

则程序运行结果为:

ReadTimes is: 1, the RecordInfo is:
100001
100002
100003
100004
100005
ReadTimes is: 2, the RecordInfo is:
100006
100007
100008
100009
100010
ReadTimes is: 3, the RecordInfo is:
100011

可见,即使文件中存在空行,程序也能够正常处理。

六、总结

本文对分批读取文件中数据的程序流程进行了介绍,并给出了C程序实现。在实际的软件开发项目中,每个文件包含的记录条数要多很多,但基本的程序编写流程是一样的。大家可以根据实际需要对本文中的程序进行修改来满足具体的要求。

往期精彩

五分钟读懂TCP 协议


为Linux应用构造有限状态机


专为MCU项目开发提速的代码框架BabyOS


嵌入式C语言代码优化方案(深度好文,建议花时间研读并收藏)


stm32cubeMX学习、USB DFU(Download Firmware Update)固件更新

目录
相关文章
|
机器学习/深度学习 算法 数据可视化
JAMA | 机器学习中的可解释性:SHAP分析图像复刻与解读
JAMA | 机器学习中的可解释性:SHAP分析图像复刻与解读
2581 1
|
Ubuntu Linux C语言
Ubuntu下安装vscode,并解决终端打不开vscode的问题
Ubuntu下安装vscode,并解决终端打不开vscode的问题
1597 0
|
存储 编译器 C语言
【数据结构】C语言实现链队列(附完整运行代码)
【数据结构】C语言实现链队列(附完整运行代码)
265 0
|
存储 Rust 自然语言处理
C代码演示WebAssembly工作流程
【2月更文挑战第3天】 工作流程: * C 代码使用 Emssripten 工具编译为 wasm 后缀的二进制文件,同时可以生成访问wasm的js胶水代码和html代码 * wasm后缀的二进制格式文件的文本表示方式为后缀为wat格式的文本文件,方便在编辑器和浏览器开发者工具中查看 * 可以使用wabt工具将wat格式的文本文件直接打包成wasm的二进制文件 * 使用WebAssemblyJavascriptAPI发起对wasm的调用 * 编写胶水代码 * 使用fetch/xhr获取wasm * 借助胶水代码访问wasm中的函数
282 0
|
存储 Java C++
C++ 引用和指针:内存地址、创建方法及应用解析
C++中的引用是现有变量的别名,创建时需用`&`运算符,如`string &meal = food;`。指针存储变量的内存地址,使用`*`创建,如`string* ptr = &food;`。引用必须初始化且不可为空,而指针可初始化为空。引用在函数参数传递和提高效率时有用,指针适用于动态内存分配和复杂数据结构操作。选择使用取决于具体需求。
231 9
|
移动开发 前端开发 小程序
分享118个HTML公司企业模板,总有一款适合您
分享118个HTML公司企业模板,总有一款适合您
313 2
|
JavaScript
Element el-radio 单选框详解
本文目录 1. 用途 2. 单选框 3. 单选框样式 4. 单选框组 4. 单选框组样式 5. 尺寸调节 6. 绑定值变化事件 7. 小结
1841 0
Element el-radio 单选框详解
|
9月前
|
Linux
linux查看目录下的文件夹命令,find查找某个目录,但是不包括这个目录本身?
通过本文的介绍,您应该对如何在 Linux 系统中查看目录下的文件夹以及使用 `find` 命令查找特定目录内容并排除该目录本身有了清晰的理解。掌握这些命令和技巧,可以大大提高日常文件管理和查找操作的效率。 在实际应用中,灵活使用这些命令和参数,可以帮助您快速定位和管理文件和目录,满足各种复杂的文件系统操作需求。
905 8
|
存储 C语言
数据结构基础详解(C语言): 栈与队列的详解附完整代码
栈是一种仅允许在一端进行插入和删除操作的线性表,常用于解决括号匹配、函数调用等问题。栈分为顺序栈和链栈,顺序栈使用数组存储,链栈基于单链表实现。栈的主要操作包括初始化、销毁、入栈、出栈等。栈的应用广泛,如表达式求值、递归等场景。栈的顺序存储结构由数组和栈顶指针构成,链栈则基于单链表的头插法实现。
1321 3
支付系统30-------支付宝支付---支付成功异步通知----通知参数和通知结果
支付系统30-------支付宝支付---支付成功异步通知----通知参数和通知结果