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,请扫描以下二维码:
这里写图片描述

目录
相关文章
|
25天前
|
Linux Shell 网络安全
Kali Linux系统Metasploit框架利用 HTA 文件进行渗透测试实验
本指南介绍如何利用 HTA 文件和 Metasploit 框架进行渗透测试。通过创建反向 shell、生成 HTA 文件、设置 HTTP 服务器和发送文件,最终实现对目标系统的控制。适用于教育目的,需合法授权。
56 9
Kali Linux系统Metasploit框架利用 HTA 文件进行渗透测试实验
|
11天前
|
Ubuntu Linux Go
golang编译成Linux可运行文件
本文介绍了如何在 Linux 上编译和运行 Golang 程序,涵盖了本地编译和交叉编译的步骤。通过这些步骤,您可以轻松地将 Golang 程序编译成适合 Linux 平台的可执行文件,并在目标服务器上运行。掌握这些技巧,可以提高开发和部署 Golang 应用的效率。
85 14
|
10天前
|
存储 NoSQL Linux
linux积累-core文件是干啥的
核心文件是Linux系统在程序崩溃时生成的重要调试文件,通过分析核心文件,开发者可以找到程序崩溃的原因并进行调试和修复。本文详细介绍了核心文件的生成、配置、查看和分析方法
41 6
|
12天前
|
存储 NoSQL Linux
linux之core文件如何查看和调试
通过设置和生成 core 文件,可以在程序崩溃时获取详细的调试信息。结合 GDB 等调试工具,可以深入分析 core 文件,找到程序崩溃的具体原因,并进行相应的修复。掌握这些调试技巧,对于提高程序的稳定性和可靠性具有重要意义。
59 6
|
2月前
|
Linux 开发工具 Perl
在Linux中,有一个文件,如何删除包含“www“字样的字符?
在Linux中,如果你想删除一个文件中包含特定字样(如“www”)的所有字符或行,你可以使用多种文本处理工具来实现。以下是一些常见的方法:
45 5
|
2月前
|
安全 Linux 数据安全/隐私保护
在 Linux 系统中,查找文件所有者是系统管理和安全审计的重要技能。
在 Linux 系统中,查找文件所有者是系统管理和安全审计的重要技能。本文介绍了使用 `ls -l` 和 `stat` 命令查找文件所有者的基本方法,以及通过文件路径、通配符和结合其他命令的高级技巧。还提供了实际案例分析和注意事项,帮助读者更好地掌握这一操作。
57 6
|
2月前
|
Linux
在 Linux 系统中,`find` 命令是一个强大的文件查找工具
在 Linux 系统中,`find` 命令是一个强大的文件查找工具。本文详细介绍了 `find` 命令的基本语法、常用选项和具体应用示例,帮助用户快速掌握如何根据文件名、类型、大小、修改时间等条件查找文件,并展示了如何结合逻辑运算符、正则表达式和排除特定目录等高级用法。
143 6
|
1月前
|
存储 Oracle 安全
服务器数据恢复—LINUX系统删除/格式化的数据恢复流程
Linux操作系统是世界上流行的操作系统之一,被广泛用于服务器、个人电脑、移动设备和嵌入式系统。Linux系统下数据被误删除或者误格式化的问题非常普遍。下面北亚企安数据恢复工程师简单聊一下基于linux的文件系统(EXT2/EXT3/EXT4/Reiserfs/Xfs) 下删除或者格式化的数据恢复流程和可行性。
|
前端开发 rax Linux
Linux 程序 Linux编译 Linux编译过程的来龙去脉
Linux 程序编译过程的来龙去脉 大家肯定都知道计算机程序设计语言通常分为机器语言、汇编语言和高级语言三类。高级语言需要通过翻译成机器语言才能执行,而翻译的方式分为两种,一种是编译型,另一种是解释型,因此我们基本上将高级语言分为两大类,一种是编译型语言,例如C,C++,Java,另一种是解释型语言,例如Python、Ruby、MATLAB 、JavaScript。
1235 0
|
2月前
|
Linux 网络安全 数据安全/隐私保护
Linux 超级强大的十六进制 dump 工具:XXD 命令,我教你应该如何使用!
在 Linux 系统中,xxd 命令是一个强大的十六进制 dump 工具,可以将文件或数据以十六进制和 ASCII 字符形式显示,帮助用户深入了解和分析数据。本文详细介绍了 xxd 命令的基本用法、高级功能及实际应用案例,包括查看文件内容、指定输出格式、写入文件、数据比较、数据提取、数据转换和数据加密解密等。通过掌握这些技巧,用户可以更高效地处理各种数据问题。
161 8