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

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

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

图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程序实现。在实际的软件开发项目中,每个文件包含的记录条数要多很多,但基本的程序编写流程是一样的。大家可以根据实际需要对本文中的程序进行修改来满足具体的要求。



本人微信公众号:zhouzxi,请扫描以下二维码:

时间: 2024-10-21 10:28:06

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

代码-从服务器上下载的压缩文件,通过流的方式怎么读取文件中的内容。

问题描述 从服务器上下载的压缩文件,通过流的方式怎么读取文件中的内容. 如何用java代码实现压缩文件的读取? 例如从银行服务器上下载对账文件后,为了不在本地保存文件. 压缩文件中的文件格式是俩个文本文件,怎么用流的方式读取到压缩文件中的文件内容. 解决方案 ZipEntry http://daoshud1.iteye.com/blog/2012362 解决方案二: http://www.cnblogs.com/kgdxpr/archive/2013/05/20/3088254.html 解决方

c++-用C++读取文件中特定行的某几列数据并输出到另一个文件

问题描述 用C++读取文件中特定行的某几列数据并输出到另一个文件 AR ZIMM 2014 06 30 00 00 0.000000 2 2.175456910513e-08 1.929140019560e-11AR ZWE2 2014 06 30 00 00 0.000000 2 -6.930289135325e-03 2.317673679230e-11AS G01 2014 06 30 00 00 0.000000 2 1.652894267903e-05 1.737915981300e-

如何用Java编写读取txt文件中数据并播放出来的软件,该怎么弄???

问题描述 如何用Java编写读取txt文件中数据并播放出来的软件,该怎么弄?? 解决方案 解决方案二:播放出来?不懂解决方案三:javax.sound.midi结合java.io自己找文档看看

Linux下按照时间和大小生成新文件的程序流程及其C代码实现

一.概述 在实际的软件开发项目中,会出现按照时间和大小生成新文件的需求.例如,某软件需求的描述如下: 按照如下两个条件之一生成新的文件: 第一,新的一天到来. 第二,文件的大小超过阈值. 本文详细介绍了根据时间和大小生成新文件的程序流程,并给出了C程序实现. 二.算法设计 对于这个按照不同的条件生成新文件的需求,在编写代码之前,我们要认真考虑以下问题: 1.如何知道当前写文件的时间与上次时间相比,是新的一天? 对于这个问题,最简单的做法是将上次写完文件之后的时间保存在内存中,等下次写文件之前读取

Linux下合并前缀相同的文件的程序流程及其C代码实现

一.概述 在实际的软件开发项目中,会出现对多个前缀(或后缀)相同的文件进行合并的需求.也就是说,将这些前缀(或后缀)相同的文件中的内容合并到一个文件中.这些文件的来源可能是前一流程中程序生成的文件,也可能是其他模块生成的文件. 例如,我们要将前缀相同(以"Test_"作为前缀)的Test_1.txt和Test_2.txt文件中的内容合并到ResultFile.txt文件中,如果Test_1.txt文件中的内容为: AAAAA Test_2.txt文件中的内容为: BBBBB 那么Res

线程-java读取文件插入到数据库程序

问题描述 java读取文件插入到数据库程序 在OEPE上开发一个java项目,实现2个线程同时循环往Oracle中插入staff.txt中读到的数据,表结构随意,id自增,两线程无限循环,不使用框架,直接在Junit启动. 解决方案 java实现读取XML文件数据插入到数据库中 解决方案二: 首先,OEPE是什么东西呢?这个文件由两个线程同时读取吗?这个可以是一个建单的应用,定义一个线程类,其run主要就是解析文件的内容插入到数据库.然后在main函数中同时启动两个线程,处理文件内容.

access-C#如何读取.accdb中数据

问题描述 C#如何读取.accdb中数据 现有access的.accdb文件(两列数据),用C#如何将每一列数据分别存入数组? 解决方案 C# 程序读取Excel数据 解决方案二: 这个简单,开两个数组,用 datareader 读一次,分别添加进去.

c++读取文件中的链表存取问题

问题描述 c++读取文件中的链表存取问题 这是一个读取文件中的链表,然后再存进新的链表为本次操作所使用,但是在存到新链表中 ,画红线的p2->next=p1;的时候就会报错.这是一个双向链表, 解决方案 next和prece指针的写法并没有错 感觉是你的fread有问题,应该是fread((&p1, sizeof(Doctor), 1, fp)) != EOF 你sizeof一个指针,永远是4 解决方案二: 1.首先fread的用法有问题吧,fread一般就读取字符串,你那个Doctor的结

mongodb mmap内存映射是把文件中数据全部映射到内存中的吗?

问题描述 mongodb mmap内存映射是把文件中数据全部映射到内存中的吗? 资料上说:在Mongodb中,其使用了操作系统底层提供的内存映射机制,即MMAP.MMAP可以把磁盘文件的一部分或全部内容直接映射到内存,这样文件中的信息位置就会在内存中有对应的地址空间,这时对文件的读写可以直接用指针来做,而不需要read/write函数了.同时操作系统会将数据刷新保存到磁盘上. 我有个疑问:这个内存映射,是把文件中数据全部映射到内存中的吗?还是只是映射一部分内容,那么这部门内容又是什么的呢? 请专