一则表驱动法的应用实例
2014-05-20 15:02
387 查看
1 需求场景
考虑如下需求场景:终端按固定时间间隔(单位为分钟)生成诊断日志(格式为UserName-Status-yyyy-mm-dd-hh-mm.log),并上传至服务器。若终端与服务器的传输通道中断,则终端本地暂存最新的N个日志文件,即第(N+1)个周期生成的新日志将覆盖第1个周期的旧日志,以此类推。待传输恢复后,终端一次性上传该N个日志。
本文主要讨论该需求中“最新日志覆盖最旧日志”的功能点。为突出层次,文中“覆盖”用先删除旧日志后创建新日志实现。实际中先删后建和先建后删各有优点,前者适于内存受限(如仅允许存在N个固定大小的日志),后者更为安全(避免创建新日志失败但已删除旧日志)。
创建文件时调用现成库函数即可,而删除时需确定当前最旧的那个文件。下文将介绍几种删除判决的实现方式(时间复杂度依次降低)。
2 实现思路
2.1 比较文件的创建时间
Linux系统中文件没有创建时间的概念,只有访问时间(atime)、修改时间(mtime)和状态改动时间(ctime)。因该需求中日志创建后立即写入内容,其后内容和状态(权限与属性等)均不再改变,故可用mtime或ctime表征创建时间。调用stat库函数即可获取日志的三种时间,比较各日志的mtime或ctime(整数)信息即可。
#include <sys/time.h> #define TIME_ELAPSED(codeToTime) do{ \ struct timeval beginTime, endTime; \ gettimeofday(&beginTime, NULL); \ {codeToTime;} \ gettimeofday(&endTime, NULL); \ long secTime = endTime.tv_sec - beginTime.tv_sec; \ long usecTime = endTime.tv_usec - beginTime.tv_usec; \ printf("[%s(%d)]Elapsed Time: SecTime = %lds, UsecTime = %ldus!\n", __FUNCTION__, __LINE__, secTime, usecTime); \ }while(0) #include <unistd.h> void CalcTime1(void){ unsigned short wFileIdx = 0; for(; wFileIdx < 1; wFileIdx++){ //time_t精度为秒,批量测试文件创建时需作秒级延迟; //但这样会影响计时统计,因为sleep会"淹没"CreateLogFile1(单次执行微妙级) //sleep(1); char szFileName[FILE_NAME_LEN] = {0}; sprintf(szFileName, "Log-Clover-%05d.log", wFileIdx); CreateLogFile1(szFileName); } } void CalcTime2(void){ unsigned short wFileIdx = 0; for(; wFileIdx < 1000; wFileIdx++){ char szFileName[FILE_NAME_LEN] = {0}; sprintf(szFileName, "Log-Clover-%05d.log", wFileIdx); CreateLogFile2(szFileName); } } void CalcTime3(void){ unsigned short wFileIdx = 0; for(; wFileIdx < 1000; wFileIdx++){ char szFileName[FILE_NAME_LEN] = {0}; sprintf(szFileName, "Log-Clover-%05d.log", wFileIdx); CreateLogFile3(szFileName); } } int main(void){ TIME_ELAPSED(CalcTime1()); TIME_ELAPSED(CalcTime2()); TIME_ELAPSED(CalcTime3()); DIR *pDir = NULL; TIME_ELAPSED(pDir = opendir(gDirectoryName)); TIME_ELAPSED(readdir(pDir)); struct stat tFileStatus; //文件状态信息 char szAbsFile[DIR_FILE_LEN] = {0}; //文件绝对路径 sprintf(szAbsFile, "%s/%s", gDirectoryName, "Log-Clover-00002.log"); TIME_ELAPSED(stat(szAbsFile, &tFileStatus)); TIME_ELAPSED(remove(szAbsFile)); FILE *pFile = NULL; TIME_ELAPSED(pFile = fopen(szAbsFile, "a+")); TIME_ELAPSED(fputs(szAbsFile, pFile)); TIME_ELAPSED(fclose(pFile)); TIME_ELAPSED(closedir(pDir)); TIME_ELAPSED(strcmp("Log-Clover-00000.log","Log-Clover-00001.log")); TIME_ELAPSED({int i=0;for(;i<10000;i++){strcmp("Log-00000","Log-00001");}}); TIME_ELAPSED({int i=0;for(;i<10000;i++){int new=20;if(FILE_NUM!=new+1){int old=new+1;}}}); TIME_ELAPSED(int new=20;if(FILE_NUM!=new+1){int old=new+1;}); return 0; }
View Code
统计结果如下所示:
对象 | 条件 | 耗时(us) |
2.1: CalcTime1() | 单次 | 792 |
2.2: CalcTime2() | 单次 | 214 |
2.2: CalcTime2() | FILE_NUM=30,循环1000次 | 274357 |
2.4: CalcTime3() | FILE_NUM=30,循环1000次 | 77789 |
opendir() | 单次 | 81 |
readdir() | 单次 | 13 |
stat() | 单次 | 9 |
remove() | 单次 | 78 |
fopen() | 单次 | 33 |
fputs() | 单次 | 8 |
fclose() | 单次 | 39 |
closedir() | 单次 | 8 |
strcmp() | 单次 | 2 |
strcmp() | 循环10000次 | 27 |
Oldest = (Latest + 1) mod FILE_NUM | 循环10000次 | 36 |
Oldest = (Latest + 1) mod FILE_NUM | 单次 | 1 |
注意:计时结果仅作粗略参考,且每次统计时结果可能略有不同。 |
5 总结
本文给出的表驱动法适用于如下场景:在按照时空顺序依次创建的若干对象中,查找符合指定时空规则的某个对象(如第N个最老对象),而不关心对象内部信息。
相关文章推荐
- BIEE CCS应用实例一则 使用CSS 更改分页控件位置
- Oracle SQL行列转换应用实例一则
- 数据库规范化三个范式应用实例
- [转载][翻译] 利用JSF、SpringFramework和Hibernate构建Web应用的实例讲述
- SAS9-IT技术应用-通过JAVA访问SAS实例
- 利用JSF、SpringFramework和Hibernate构建Web应用的实例讲述
- CFML中URLEncodedFormat应用实例
- DirectDraw6的初级编程应用 —— 配合实例讲解,让你迅速入门
- 元函数在SQL查询中应用实例分析【续上篇】
- ASP.net随机数应用实例
- 数据库中的XML应用实例
- XSL应用实例
- 串口中断应用实例
- 利用JSF、SpringFramework和Hibernate构建Web应用的实例讲述
- IE里的数据岛应用的最佳实例
- 数据库中的XML应用实例
- 算法设计应用实例
- JBuilder 4 Enterprise 开发CORBA/WEB应用实例
- 遗传算法的发展现状与应用实例
- 利用JSF、SpringFramework和Hibernate构建Web应用的实例讲述