0
点赞
收藏
分享

微信扫一扫

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


一、问题描述

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

 

二、算法流程

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

三、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) 本程序中使用了多个文件处理函数,如:fopen、fputs、fflush、fclose、fseek、fread、fwrite等。各位读者可以据此体会不同文件处理函数的用法。

        (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文件,内容如下:

写文件头的算法流程及C代码实现_版本号_02


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

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;
}
}




举报

相关推荐

0 条评论