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

一、概述
在实际的软件开发项目中,会出现按照时间和大小生成新文件的需求。例如,某软件需求的描述如下:

按照如下两个条件之一生成新的文件:
第一,新的一天到来。
第二,文件的大小超过阈值。

本文详细介绍了根据时间和大小生成新文件的程序流程,并给出了C程序实现。

二、算法设计
对于这个按照不同的条件生成新文件的需求,在编写代码之前,我们要认真考虑以下问题:
1.如何知道当前写文件的时间与上次时间相比,是新的一天?
对于这个问题,最简单的做法是将上次写完文件之后的时间保存在内存中,等下次写文件之前读取内存获得这个时间,并与当前时间进行比较。如果两个时间一样,则表示新的一天未到来,不用写入新的文件中。
但是,如果程序在运行的过程中崩溃了,那么内存中的数据会全部丢失。不管新的一天是否到来,当程序重新启动之后,又要生成新的文件。这显然与需求的描述不符。
为了避免这种情况,我们在本地用一个控制文件来记录上次写文件时的时间和序列号的值。每次程序启动的时候,便读取文件中的内容,解析之后进行后续处理。

2.如何判断当前文件的大小超过阈值?
在文件操作函数中,有一个ftell函数用于获取当前文件的大小(单位为字节)。当文件大小超过阈值时,我们只需要将生成文件的序列号加1即可。下次写文件的时候,文件内容便会被写入到新的文件中。

3.代码功能模块化
为了体现出代码的可读性,尽量将重要的功能封装成一个函数,这样独立的模块使用起来比较的方便,同时也方便后期的维护。
在本程序中,可以将以下功能封装为函数:
(1) 获取控制文件中的时间和序列号。
(2) 新的一天到来时程序的处理。
(3) 当前文件的大小超过阈值时程序的处理。
(4) 把内容写到本地文件中。

三、示例程序流程
希望有兴趣的同学看了附录中的程序之后,自己来试着画一下流程图,这样可以加深对程序的理解。

四、程序编译、运行和测试
我想这些还是留给读者朋友们来做吧。

五、总结
文件操作在实际的软件开发项目中占有非常重要的地位,大家从我的很多博文中就可以看出来。对于一个合格的C程序员来说,大家一定要熟练掌握相关文件操作函数的用法。

附录:完整的程序代码

/**********************************************************************
* 版权所有 (C)2015, Zhou Zhaoxiong。
*
* 文件名称:WriteLocalFile.c
* 文件标识:无
* 内容摘要:按照时间和大小生成文件
* 其它说明:无
* 当前版本:V1.0
* 作    者:Zhou Zhaoxiong
* 完成日期:20150721
*
**********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

// 数据类型重定义
typedef signed   int        INT32;
typedef signed   char       INT8;
typedef unsigned char       UINT8;
typedef unsigned short int  UINT16;
typedef unsigned int        UINT32;
typedef long     int        LONG;
typedef unsigned char       BOOL;

// 字段最大长度
#define MAX_RET_BUF_LEN     (1024)

//参数类型
#define MML_INT8_TYPE       0
#define MML_INT16_TYPE      1
#define MML_INT32_TYPE      2
#define MML_STR_TYPE        3

#define  TRUE         (BOOL)1
#define  FALSE        (BOOL)0

typedef struct
{
    UINT8   second;     /* 0-59 */
    UINT8   minute;     /* 0-59 */
    UINT8   hour;       /* 0-23 */
    UINT8   day;        /* 1-31 */
    UINT8   month;      /* 1-12 */
    UINT16  year;       /* 1994-2099 */
    UINT8   week;       /* 1-7 */
    UINT8   Count10ms;  /* 0-99 */
} ClockStruc;

// 全局变量
UINT32  g_iSeqNo         = 1;     // 序列号初始化为1
INT8    g_szLastDate[20] = {0};   // 日期时间初始化为空
INT8    g_szCtlFile[500]   = {0};

// 函数声明
void CurrentTime(ClockStruc *ptTime);
void WriteToLocalFile(UINT8 *pszContentLine);
void GetValueFromStr(UINT16 iSerialNum, UINT8 iContentType, UINT8 *pSourceStr, UINT8 *pDstStr, UINT8 cIsolater, UINT32 iDstStrSize);
void GetCtlInfo();
void WriteCtrFileForNewDay(INT8 *pszCurDate);
void WriteCtrFileBySize(INT8 *pszCurDate);
INT32 main();


/**********************************************************************
* 功能描述:主函数
* 输入参数:无
* 输出参数:无
* 返 回 值:无
* 其它说明:无
* 修改日期        版本号     修改人            修改内容
* -------------------------------------------------------------------
* 20150721        V1.0     Zhou Zhaoxiong        创建
***********************************************************************/
INT32 main()
{
    UINT8  szContentLine[1000] = {0};

    // 先获取控制文件中的日期时间和序列号
    GetCtlInfo();

    // 第一次写文件
    // 拼装写本地文件的内容
    snprintf(szContentLine, sizeof(szContentLine)-1, "123|ab|\r\n");
    // 将文件内容写入本地文件
    WriteToLocalFile(szContentLine);

    // 第二次写文件
    // 拼装写本地文件的内容
    snprintf(szContentLine, sizeof(szContentLine)-1, "56|ef|\r\n");
    // 将文件内容写入本地文件
    WriteToLocalFile(szContentLine);

    // 第三次写文件
    // 拼装写本地文件的内容
    snprintf(szContentLine, sizeof(szContentLine)-1, "21|ba|\r\n");
    // 将文件内容写入本地文件
    WriteToLocalFile(szContentLine);

    return 0;                  // main函数返回0
}


/**********************************************************************
* 功能描述:获取当前时间
* 输入参数:pTime-时间结构体
* 输出参数:pTime-时间结构体
* 返 回 值:无
* 其它说明:无
* 修改日期        版本号     修改人            修改内容
* -------------------------------------------------------------------
* 20150721        V1.0     Zhou Zhaoxiong        创建
***********************************************************************/
void CurrentTime(ClockStruc *ptTime)
{
    LONG    dt           = 0;
    struct  tm      *tm1 = NULL;
    struct  timeval  tp  = {0};

    // get real clock from system
    gettimeofday(&tp, NULL);
    dt  = tp.tv_sec;
    tm1 = localtime(&dt);
    ptTime->Count10ms = tp.tv_usec / 10000;
    ptTime->year      = (UINT16)(tm1->tm_year + 1900);
    ptTime->month     = (UINT8)tm1->tm_mon + 1;
    ptTime->day       = (UINT8)tm1->tm_mday;
    ptTime->hour      = (UINT8)tm1->tm_hour;
    ptTime->minute    = (UINT8)tm1->tm_min;
    ptTime->second    = (UINT8)tm1->tm_sec;
    ptTime->week      = (UINT8)tm1->tm_wday;
    if (ptTime->week == 0)   // Sunday
    {
        ptTime->week = 7;
    }
}


/**********************************************************************
 * 功能描述: 把内容写到本地文件中
 * 输入参数: pszContentLine-一条文件记录
 * 输出参数: 无
 * 返 回 值: 无
 * 其它说明: 无
 * 修改日期            版本号            修改人           修改内容
 * ----------------------------------------------------------------------
 * 20150721             V1.0          Zhou Zhaoxiong        创建
 ************************************************************************/
void WriteToLocalFile(UINT8 *pszContentLine)
{
    FILE  *fpCtlFile           = NULL;
    INT8   szLocalFile[500]    = {0};
    FILE  *fp                  = NULL;
    INT8   szCurDate[20]       = {0};
    INT8   szBuf[200]          = {0};

    ClockStruc  tClock = {0};

    if (NULL == pszContentLine)
    {
        printf("WriteToLocalFile: input parameter is NULL.\n");
        return;
    } 

    CurrentTime(&tClock);     // 获取当前时间
    snprintf(szCurDate, sizeof(szCurDate) - 1, "%04d%02d%02d", tClock.year, tClock.month, tClock.day);

    if (strncmp(szCurDate, g_szLastDate, 8) != 0 || g_szLastDate[0] == 0)   // 日期不匹配或日期为空, 都当做新的一天处理
    {
        // 新的一天, 需重置序列号为1, 并记录当前日期到控制文件
        WriteCtrFileForNewDay(szCurDate);
    }

    snprintf(szLocalFile, sizeof(szLocalFile)-1, "%s/zhouzhaoxiong/zzx/File_%d.r", getenv("HOME"), g_iSeqNo);
    fp = fopen(szLocalFile, "a+");
    if (fp == NULL)
    {
         printf("WriteToLocalFile: open local file failed, file=%s\n", szLocalFile);
         return;
    }

    printf("WriteToLocalFile: LocalFile=%s, ContentLine=%s\n", szLocalFile, pszContentLine);

    fputs(pszContentLine, fp);
    fflush(fp);

    if (ftell(fp) >= 10)            // 当前文件大于10个字节, 则写新文件
    {
        WriteCtrFileBySize(szCurDate);
    }

    fclose(fp);
    fp = NULL;

    return;
}


/**********************************************************************
*功能描述:获取字符串中某一个字段的数据
*输入参数:iSerialNum-字段编号(为正整数)
           iContentType-需要获取的内容的类型
           pSourceStr-源字符串
           pDstStr-目的字符串(提取的数据的存放位置)
           cIsolater-源字符串中字段的分隔符
           iDstStrSize-目的字符串的长度
*输出参数:无
*返 回 值:无
*其它说明:无
*修改日期        版本号            修改人         修改内容
* --------------------------------------------------------------
* 20150721       V1.0          Zhou Zhaoxiong       创建
***********************************************************************/
void GetValueFromStr(UINT16 iSerialNum, UINT8 iContentType, UINT8 *pSourceStr, UINT8 *pDstStr, UINT8 cIsolater, UINT32 iDstStrSize)
{
    UINT8  *pStrBegin                 = NULL;
    UINT8  *pStrEnd                   = NULL;
    UINT8   szRetBuf[MAX_RET_BUF_LEN] = {0}; //截取出的字符串放入该数组中
    UINT8  *pUINT8                    = NULL;
    UINT16 *pUINT16                   = NULL;
    UINT32 *pUINT32                   = NULL;
    UINT32  iFieldLen                 = 0;     //用于表示每个字段的实际长度

    if (pSourceStr == NULL)           //对输入指针的异常情况进行判断
    {
        return;
    }
    //字段首
    pStrBegin = pSourceStr;
    while (--iSerialNum != 0)
    {
        pStrBegin = strchr(pStrBegin, cIsolater);
        if (pStrBegin == NULL)
        {
            return;
        }
        pStrBegin ++;
    }

    //字段尾
    pStrEnd = strchr(pStrBegin, cIsolater);
    if (pStrEnd == NULL)
    {
        return;
    }

    iFieldLen = (UINT16)(pStrEnd - pStrBegin);
    if(iFieldLen >= MAX_RET_BUF_LEN) //进行异常保护, 防止每个字段的值过长
    {
        iFieldLen = MAX_RET_BUF_LEN - 1;
    }

    memcpy(szRetBuf, pStrBegin, iFieldLen);

    //将需要的字段值放到pDstStr中去
    switch (iContentType)
    {
        case MML_STR_TYPE:                        //字符串类型
        {
            strncpy(pDstStr, szRetBuf, iDstStrSize);
            break;
        }

        case MML_INT8_TYPE:                       //字符类型
        {
            pUINT8   = (UINT8 *)pDstStr;
            *pDstStr = (UINT8)atoi(szRetBuf);
            break;
        }

        case MML_INT16_TYPE:                      // short int类型
        {
            pUINT16  = (UINT16 *)pDstStr;
            *pUINT16 = (UINT16)atoi(szRetBuf);
            break;
        }

        case MML_INT32_TYPE:                      // int类型
        {
            pUINT32  = (UINT32 *)pDstStr;
            *pUINT32 = (UINT32)atoi(szRetBuf);
            break;
        }

        default:                                  // 一定要有default分支
        {
            return;
        }
    }

    return;
}


/**********************************************************************
* 功能描述:获取控制文件中的时间和序列号
* 输入参数:无
* 输出参数:无
* 返 回 值:无
* 其它说明:无
* 修改日期        版本号     修改人            修改内容
* -------------------------------------------------------------------
* 20150721        V1.0     Zhou Zhaoxiong        创建
***********************************************************************/
void GetCtlInfo()
{
    FILE *fpCtlFile   = NULL;
    INT8  szBuf[500]  = {0};

    // 控制文件存放在当前用户的etc目录下, 命名为CtrFile.txt
    snprintf(g_szCtlFile, sizeof(g_szCtlFile) - 1, "%s/etc/CtrFile.txt", getenv("HOME"));
    fpCtlFile = fopen(g_szCtlFile, "r");
    if (fpCtlFile != NULL)    // 文件打开成功
    {
        fgets(szBuf, sizeof(szBuf), fpCtlFile);    // 读取文件内容

        GetValueFromStr(1, MML_STR_TYPE,   szBuf, (UINT8 *)g_szLastDate, '|', sizeof(g_szLastDate));       // 获取日期字段内容

        GetValueFromStr(2, MML_INT32_TYPE, szBuf, (UINT8 *)&g_iSeqNo,    '|', sizeof(g_iSeqNo));           // 获取序列号字段内容

        fclose(fpCtlFile);
        fpCtlFile = NULL;
    }

    return;
}


/**********************************************************************
* 功能描述:新的一天, 重置序列号为1, 并记录当前日期到控制文件
* 输入参数:pszCurDate-当前时间
* 输出参数:无
* 返 回 值:无
* 其它说明:无
* 修改日期        版本号     修改人            修改内容
* -------------------------------------------------------------------
* 20150721        V1.0     Zhou Zhaoxiong        创建
***********************************************************************/
void WriteCtrFileForNewDay(INT8 *pszCurDate)
{
    FILE  *fpCtlFile  = NULL;
    INT8   szBuf[200] = {0};

    if (pszCurDate == NULL)
    {
        return;
    }

    g_iSeqNo = 1;                       // 重置序列号为1

    strcpy(g_szLastDate, pszCurDate);   // 对全局时间变量赋值, 防止其为空而导致所有记录写入到一个文件中

    fpCtlFile = fopen(g_szCtlFile, "w");
    if (fpCtlFile != NULL)
    {
        sprintf(szBuf, "%s|%d|", pszCurDate, g_iSeqNo);
        fputs(szBuf, fpCtlFile);
        fclose(fpCtlFile);
        fpCtlFile = NULL;

        printf("WriteCtrFileForNewDay: a new day is coming or the program has just initialized, write control file successfully! file=%s, content=%s\n", g_szCtlFile, szBuf);
    }
    else
    {
        printf("WriteCtrFileForNewDay: write control file failed! file=%s\n", g_szCtlFile);
    }

    return;
}


/**********************************************************************
* 功能描述:当前文件大于规定大小, 则记录日期和序列号到控制文件中
* 输入参数:pszCurDate-当前时间
* 输出参数:无
* 返 回 值:无
* 其它说明:无
* 修改日期        版本号     修改人            修改内容
* -------------------------------------------------------------------
* 20150721        V1.0     Zhou Zhaoxiong        创建
***********************************************************************/
void WriteCtrFileBySize(INT8 *pszCurDate)
{
    FILE  *fpCtlFile  = NULL;
    INT8   szBuf[200] = {0};

    if (pszCurDate == NULL)
    {
        return;
    }

    g_iSeqNo ++;     // 序列号加1
    if (g_iSeqNo > 999999)      // 序列号最大值为999999
    {
        g_iSeqNo = 1;
    }

    fpCtlFile = fopen(g_szCtlFile, "w");
    if (fpCtlFile != NULL)
    {
        sprintf(szBuf, "%s|%d|", pszCurDate, g_iSeqNo);
        fputs(szBuf, fpCtlFile);
        fclose(fpCtlFile);
        fpCtlFile = NULL;

        printf("WriteCtrFileBySize: file size has reached max size, write control file successfully! file=%s, content=%s\n", g_szCtlFile, szBuf);
    }
    else
    {
        printf("WriteCtrFileBySize: write control file failed! file=%s\n", g_szCtlFile);
    }

    return;
}

本人微信公众号:zhouzxi,请扫描以下二维码:
这里写图片描述

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

知识的港湾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值