写文件头的算法流程及C代码实现

一、问题描述

       将多条记录写入文件中,每条记录占一行。每写入一条记录,要计算当前文件中所有记录的大小(精确到字节)和记录条数,并写到文件的第一行(即文件头)。为了便于区分,文件记录的大小和文件中记录条数各占10个字节,左对齐,不足的位补以空格。

 

二、算法流程

三、C代码实现

/**********************************************************************
* 版权所有 (C)2015, Zhou Zhaoxiong。
*
* 文件名称:WriteFileHeader.c
* 文件标识:无
* 内容摘要:测试文件头的写入
* 其它说明:无
* 当前版本:V1.0
* 作    者:Zhou Zhaoxiong
* 完成日期:20150113
*
**********************************************************************/
#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      


// 重定义数据类型
typedef signed   char       INT8;
typedef unsigned char       UINT8;
typedef unsigned int        UINT32;
typedef signed   int        INT32;

// 函数声明
void WriteToFile(UINT8 *pszContentLine);
INT32 main();

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

    // 第一次写文件
    // 拼装写本地文件的内容
    snprintf(szContentLine, sizeof(szContentLine)-1, "1234|abcd|\r\n");
    // 将文件内容写入本地文件
    WriteToFile(szContentLine);
	
    // 第二次写文件
    // 拼装写本地文件的内容
    snprintf(szContentLine, sizeof(szContentLine)-1, "5678|efgh|\r\n");
    // 将文件内容写入本地文件
    WriteToFile(szContentLine);

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

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


/**********************************************************************
 * 功能描述: 写本地文件, 同时更新文件头
 * 输入参数: pszContentLine: 一条文件记录
 * 输出参数: 无
 * 返 回 值: 无
 * 其它说明: 文件头的长度为20字节, 前10字节为写入文件内容的大小, 后10字节为文件内容的条数
 * 修改日期            版本号            修改人           修改内容
 * ----------------------------------------------------------------------
*  20150113             V1.0          Zhou Zhaoxiong        创建
 ************************************************************************/
void WriteToFile(UINT8 *pszContentLine)
{
    INT8   szFileName[500]     = {0};
    FILE  *fp                  = NULL;
    UINT8  iIsNewCdrFile       = 0;
    UINT8  szFileHeader[100]   = {0};
    UINT8  szTmpBuf[50]        = {0};
    UINT32 iSize               = 0;
    UINT32 iCount              = 0;
    UINT32 iLen                = 0;
    
    if (NULL == pszContentLine)
    {
        printf("WriteToFile: input parameter is NULL.\n");
        return;
    }
    
    snprintf(szFileName, sizeof(szFileName)-1, "/home/zhou/zhouzhaoxiong/TestFile.txt");
    
    // 判断是否为新文件
    if (access(szFileName, 0) == -1)
    {
        iIsNewCdrFile = 1;     // 是新文件
    }
    else
    {
        iIsNewCdrFile = 0;
    }

    fp = fopen(szFileName, "a+");
    if (fp == NULL)
    {
         printf("WriteToFile: open file failed, file=%s\n", szFileName);
         return;
    }

    // 如果是新文件, 先写文件头
    if (iIsNewCdrFile == 1)
    {
        // 新话单文件, 写入文件头
        memset(szFileHeader, 0x00, sizeof(szFileHeader));
        memset(szFileHeader, ' ', 20);    
        strcat(szFileHeader, "\r\n");       // 回车换行符
	// 文件头第一部分, 文件内容的大小
        sprintf(szTmpBuf, "%d", strlen(pszContentLine)-2);   // 要去掉最后的回车换行符的大小, 因此这里要减去2
        memcpy(szFileHeader, szTmpBuf, strlen(szTmpBuf));

	// 文件头第二部分, 文件内容的条数
        sprintf(szTmpBuf, "%d", 1);   // 写入第一条
        memcpy(szFileHeader+10, szTmpBuf, strlen(szTmpBuf));

        printf("WriteToFile: now write header to file, Count of content=%s\n", szTmpBuf);
        fputs(szFileHeader, fp);
    }

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

    fclose(fp);
    fp = NULL;     // 写入完毕要在关闭文件的同时置文件指针为空

    // 更新文件头
    if (iIsNewCdrFile == 0)       // 文件已存在
    {
        fp = fopen(szFileName, "r+");
        if (fp == NULL)
        {
             printf("WriteToFile: open file for updating header failed, file=%s\n", szFileName);
             return;
        }
    
        // 已有话单文件, 更新文件头
        memset(szFileHeader, 0x00, sizeof(szFileHeader));
        fseek(fp, 0, SEEK_SET);        // 文件第一行
        fread(szFileHeader, 20, 1, fp);
        fflush(fp);
        
	// 更新文件内容的大小
        memset(szTmpBuf, 0x00, sizeof(szTmpBuf));
        memcpy(szTmpBuf, szFileHeader, 10);
        iSize = atoi(szTmpBuf);    // 原大小
        sprintf(szTmpBuf, "%d", iSize+strlen(pszContentLine)-2);
        iLen = strlen(szTmpBuf);
        memcpy(szFileHeader, szTmpBuf, iLen);

	// 更新文件内容的条数
        memset(szTmpBuf, 0x00, sizeof(szTmpBuf));
        memcpy(szTmpBuf, szFileHeader+10, 10);
        iCount = atoi(szTmpBuf);
        sprintf(szTmpBuf, "%d", iCount+1);
        iLen = strlen(szTmpBuf);
        memcpy(szFileHeader+10, szTmpBuf, iLen);

        printf("WriteToFile: now update file header, Count of content=%s\n", szTmpBuf);
        fseek(fp, 0, SEEK_SET);
        fwrite(szFileHeader, 20, 1, fp);
        fflush(fp);

        fclose(fp);
        fp = NULL;
    }
}

     
     
    
    
   
   

 

四、程序说明

        (1) 本程序在Linux环境下用makefile文件进行编译,makefile文件的内容如下:

WriteFileHeader : WriteFileHeader.c

       gcc -c -g WriteFileHeader.c

       gcc -g -o release/WriteFileHeader WriteFileHeader.o

       rm *.o

        (2) 本程序中使用了多个文件处理函数,如:fopenfputsfflushfclosefseekfreadfwrite等。各位读者可以据此体会不同文件处理函数的用法。

        (3) 本程序演示了三次文件记录的写入过程,大家可以根据自身所需用不同的记录来对程序进行测试。

 

五、程序运行结果

        用makefile文件对程序进行编译之后,转到release目录下,执行“WriteFileHeader”命令,结果如下:

WriteToFile: now write header to file, Count of content=1

WriteToFile: now update file header, Count of content=2

WriteToFile: now update file header, Count of content=3

       查看TestFile.txt文件,内容如下:


---------------------------------------

2016年4月28日修改程序:

/**********************************************************************
* 版权所有 (C)2015, Zhou Zhaoxiong。
*
* 文件名称:WriteFileHeader.c
* 文件标识:无
* 内容摘要:测试文件头的写入
* 其它说明:无
* 当前版本:V1.0
* 作    者:Zhou Zhaoxiong
* 完成日期:20150113
*
**********************************************************************/
#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       

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

// 时间结构体
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;

// 函数声明
void WriteToFile(UINT8 *pszContentLine);
void WriteNewFileHeader(FILE *fp, UINT8 *pszContentLine);
void UpdateFileHeader(INT8 *pszFileName, UINT8 *pszContentLine);
void CurrentTime(ClockStruc *ptTime);


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

    // 第一次写文件
    // 拼装写本地文件的内容
    snprintf(szContentLine, sizeof(szContentLine)-1, "1234|abcd|\r\n");
    // 将文件内容写入本地文件
    WriteToFile(szContentLine);
    
    // 第二次写文件
    // 拼装写本地文件的内容
    snprintf(szContentLine, sizeof(szContentLine)-1, "5678|efgh|\r\n");
    // 将文件内容写入本地文件
    WriteToFile(szContentLine);

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

    // 第四次写文件
    // 拼装写本地文件的内容
    snprintf(szContentLine, sizeof(szContentLine)-1, "1234567890\r\n");
    // 将文件内容写入本地文件
    WriteToFile(szContentLine);

    return 0;
}


/**********************************************************************
 * 功能描述: 写本地文件, 同时更新文件头
 * 输入参数: pszContentLine: 一条文件记录
 * 输出参数: 无
 * 返 回 值: 无
 * 其它说明: 文件头的长度为50字节, 前10字节为写入文件内容的大小, 
              11-20字节为文件内容的条数, 21-40字节为写入最后一条文件记录时的时间
 * 修改日期            版本号            修改人           修改内容
 * ----------------------------------------------------------------------
 *  20150113             V1.0          Zhou Zhaoxiong        创建
 **********************************************************************/
void WriteToFile(UINT8 *pszContentLine)
{
    INT8   szFileName[500] = {0};
    FILE  *fp              = NULL;
    UINT8 *pszHomePath     = NULL;
    UINT8  iIsNewCdrFile   = 0;
    
    if (NULL == pszContentLine)
    {
        printf("WriteToFile: input parameter is NULL.\n");
        return;
    }

    pszHomePath = (UINT8 *)getenv("HOME");     // 获取当前用户所在的主目录
    if (pszHomePath == NULL)
    {
        return;
    }

    // 获取带路径的文件名
    snprintf(szFileName, sizeof(szFileName)-1, "%s/zhouzhaoxiong/zzx/TestFile.txt", pszHomePath);
    
    // 判断是否为新文件
    if (access(szFileName, 0) == -1)
    {
        iIsNewCdrFile = 1;     // 是新文件
    }
    else
    {
        iIsNewCdrFile = 0;
    }

    fp = fopen(szFileName, "a+");
    if (fp == NULL)
    {
         printf("WriteToFile: open file failed, file=%s\n", szFileName);
         return;
    }

    // 如果是新文件, 先写文件头
    if (iIsNewCdrFile == 1)
    {
        WriteNewFileHeader(fp, pszContentLine);
    }

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

    fclose(fp);
    fp = NULL;     // 写入完毕要在关闭文件的同时置文件指针为空

    // 更新文件头
    if (iIsNewCdrFile == 0)       // 文件已存在
    {
        UpdateFileHeader(szFileName, pszContentLine);
    }
}


/**********************************************************************
 * 功能描述: 首次写文件头
 * 输入参数: pszContentLine: 一条文件记录
 * 输出参数: 无
 * 返 回 值: 无
 * 其它说明: 无
 * 修改日期            版本号            修改人           修改内容
 * ----------------------------------------------------------------------
 * 20160428            V1.0          Zhou Zhaoxiong        创建
 *********************************************************************/
void WriteNewFileHeader(FILE *fp, UINT8 *pszContentLine)
{
    UINT8  szFileHeader[100] = {0};
    UINT8  szTmpBuf[50]      = {0};

    ClockStruc tCurTime      = {0};

    if (NULL == fp || NULL == pszContentLine)
    {
        printf("WriteNewFileHeader: input parameter(s) is NULL.\n");
        return;
    }
    
    // 新文件, 写入文件头
    memset(szFileHeader, ' ', 40);    
    strcat(szFileHeader, "\r\n");       // 回车换行符

    // 文件头第一部分, 文件内容的大小
    snprintf(szTmpBuf, sizeof(szTmpBuf)-1, "%d", strlen(pszContentLine)-2);   // 要去掉最后的回车换行符的大小, 因此这里要减去2
    memcpy(szFileHeader, szTmpBuf, strlen(szTmpBuf));

    // 文件头第二部分, 文件内容的条数
    snprintf(szTmpBuf, sizeof(szTmpBuf)-1, "%d", 1);   // 写入第一条
    memcpy(szFileHeader+10, szTmpBuf, strlen(szTmpBuf));

    // 文件头第三部分, 写入最后一条文件记录时的时间
    CurrentTime(&tCurTime);  
    memset(szTmpBuf, 0x00, sizeof(szTmpBuf));
    snprintf(szTmpBuf, sizeof(szTmpBuf)-1, "%d.%d.%d %d:%d:%d", tCurTime.year, tCurTime.month,  tCurTime.day, 
                                                                tCurTime.hour, tCurTime.minute, tCurTime.second);
    memcpy(szFileHeader+20, szTmpBuf, strlen(szTmpBuf));

    printf("WriteNewFileHeader: now write new file header, Count of content=%d\n", 1);

    fputs(szFileHeader, fp);
}


/**********************************************************************
 * 功能描述: 更新文件头
 * 输入参数: pszFileName: 文件名
              pszContentLine: 一条文件记录
 * 输出参数: 无
 * 返 回 值: 无
 * 其它说明: 无
 * 修改日期            版本号            修改人           修改内容
 * ----------------------------------------------------------------------
 * 20160428            V1.0          Zhou Zhaoxiong        创建
 *********************************************************************/
void UpdateFileHeader(INT8 *pszFileName, UINT8 *pszContentLine)
{
    UINT8  szFileHeader[100] = {0};
    UINT8  szTmpBuf[50]      = {0};
    FILE  *fp                = NULL;
    UINT32 iSize             = 0;
    UINT32 iLen              = 0;
    UINT32 iCount            = 0;

    ClockStruc tCurTime      = {0};

    if (NULL == pszFileName || NULL == pszContentLine)
    {
        printf("UpdateFileHeader: input parameter(s) is NULL.\n");
        return;
    }
    
    fp = fopen(pszFileName, "r+");
    if (fp == NULL)
    {
        printf("UpdateFileHeader: open file for updating header failed, file=%s\n", pszFileName);
        return;
    }
    
    // 已有文件, 更新文件头
    memset(szFileHeader, 0x00, sizeof(szFileHeader));
    fseek(fp, 0, SEEK_SET);        // 文件第一行
    fread(szFileHeader, 40, 1, fp);
    fflush(fp);
        
    // 更新文件内容的大小
    memset(szTmpBuf, 0x00, sizeof(szTmpBuf));
    memcpy(szTmpBuf, szFileHeader, 10);
    iSize = atoi(szTmpBuf);    // 原大小
    snprintf(szTmpBuf, sizeof(szTmpBuf)-1, "%d", iSize+strlen(pszContentLine)-2);
    iLen = strlen(szTmpBuf);
    memcpy(szFileHeader, szTmpBuf, iLen);

    // 更新文件内容的条数
    memset(szTmpBuf, 0x00, sizeof(szTmpBuf));
    memcpy(szTmpBuf, szFileHeader+10, 10);
    iCount = atoi(szTmpBuf);
    snprintf(szTmpBuf, sizeof(szTmpBuf)-1, "%d", iCount+1);
    iLen = strlen(szTmpBuf);
    memcpy(szFileHeader+10, szTmpBuf, iLen);

    // 更新时间
    CurrentTime(&tCurTime);  
    memset(szTmpBuf, 0x00, sizeof(szTmpBuf));
    snprintf(szTmpBuf, sizeof(szTmpBuf)-1, "%04d.%02d.%02d %02d:%02d:%02d", tCurTime.year, tCurTime.month,  tCurTime.day, 
                                                                            tCurTime.hour, tCurTime.minute, tCurTime.second);
    iLen = strlen(szTmpBuf);
    memcpy(szFileHeader+20, szTmpBuf, iLen);
    
    printf("UpdateFileHeader: now update file header, Count of content=%d\n", iCount+1);
    fseek(fp, 0, SEEK_SET);
    fwrite(szFileHeader, 40, 1, fp);
    fflush(fp);

    fclose(fp);
    fp = NULL;
}


/**********************************************************************
* 功能描述:当前时间
* 输入参数:ptTime-时间结构体
* 输出参数:ptTime-时间结构体
* 返 回 值:无
* 其它说明:无
* 修改日期        版本号         修改人          修改内容
* -------------------------------------------------------------------
* 20160428        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;
    }
}

      
      
     
     
    
    
   
   



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

周兆熊-IT

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

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

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

打赏作者

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

抵扣说明:

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

余额充值