VC++获取文件的修改时间,定期清理若干天之前的日志文件(附源码)
Posted dvlinker
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了VC++获取文件的修改时间,定期清理若干天之前的日志文件(附源码)相关的知识,希望对你有一定的参考价值。
目录
为了方便排查软件运行过程中的问题,很多软件在运行过程中会将运行日志写到指定位置的日志文件中,日志记录已经成为大多数软件的一个标配。随着软件的长时间持续运行,日志文件会越来越多,会占用展会用越来越多的磁盘空间。一般情况下,我们只需要出问题时间点附近的日志,若干天前的运行日志可能就不再需要了。这就需要在软件中增加一个日志清理机制,定时去清除一些老旧的日志文件。本文就来详细地讲述一种清理日志文件的思路和方法。
1、日志文件生成控制策略
一般情况下,不能将所有生成的日志都写到一个文件中,如果将每天生成的日志都写到同一个文件中,文件会变得越来越大,越来越臃肿,以至于打开文件时都需要很长时间。所以我们在生成日志时,都会做一些控制策略,在需要的时候切换到新的文件去写(切文件)。
切文件的好处,一是每个文件不会太大,二是方便老旧日志文件的清理(我们可以清理指定时间之前的所有日志文件)。
比如为了方便查看,有的软件每天都会按照当天的日期重新生成一个日志文件,文件的名称中会标记上当天的日期,如下:
这个出问题时,我们就可以查看对应日期的日志去分析就好了。
再比如有的软件或者模块,他们的日志控制机制是不同的。比如他们在生成日志时,日志文件名称并不会带上日期,他们会控制每个日志文件的大小,当文件达到上限值(比如50MB)时,会自动切换文件,如下所示:
虽然文件名称中没有日期,但文件中的每条日志都有带上年月日时分秒的时间戳,甚至精确到毫秒。出问题时,我们通过出问题的时间点,到这些文件中找到对应时间点的文件,去查看去分析就可以了。
2、日志文件清理机制说明
随着程序的持续运行,日志文件会越来越多,我们要及时地将不要的老旧日志给清理掉,将占用的磁盘给及时地释放掉。此处的清理机制是建立在日志文件自动切换到(自动切换到新的文件中)的基础上的。
我们可以遍历日志路径下的所有文件,获取这些文件的最后修改时间,与当前时间点做比较,将若干天之前的日志文件都删除掉,只保留最近若干天的日志。当然,这也要求我们出问题时要及时地去拿日志文件,时间拖久了,日志可能就被删除了。
我们可以在软件启动时开启一个新的线程,去做日志的检测和清理工作,完成后就退出线程。那对于电脑一直没关机、软件一直运行的场景呢?我们可以开启一个定时,如果持续运行了一段时间后,自动开启新的线程去做日志检测与清理工作。
3、清理日志的代码实现
3.1 获取单个文件的修改时间
我们先调用系统API函数FindFirstFile获取日志文件的最后修改时间,然后调用API函数FileTimeToLocalFileTime将修改时间转换成本地文件时间,接着再调用FileTimeToSystemTime函数将时间转成SYSTEMTIME结构体时间,然后再转成64位整型时间。相关代码如下所示:
// 获取日志文件的最后修改时间
// 参数:strFilePath[in], sysTime[out]
time_t GetFileModifyTime( LPCTSTR strFilePath )
SYSTEMTIME sysTime;
HANDLE hFile = INVALID_HANDLE_VALUE;
FILETIME localFileTime;
WIN32_FIND_DATA wfd;
memset( &wfd, 0, sizeof(wfd) );
hFile = FindFirstFile( strFilePath, &wfd );
if ( hFile == INVALID_HANDLE_VALUE )
return 0;
BOOL bRet = FileTimeToLocalFileTime( &wfd.ftLastWriteTime, &localFileTime );
if ( !bRet )
return 0;
memset( &sysTime, 0, sizeof(sysTime) );
bRet = FileTimeToSystemTime( &localFileTime, &sysTime );
if ( !bRet )
return 0;
FindClose( hFile );
// 老版本对tm结构体变量的初始化是不科学的,根据之前对本地时间和UTC时间及时区的研究,
struct tm tmFileTime;
memset( &tmFileTime, 0xFF, sizeof(tmFileTime) );
tmFileTime.tm_year = sysTime.wYear - 1900;
tmFileTime.tm_mon = sysTime.wMonth - 1;
tmFileTime.tm_mday = sysTime.wDay;
tmFileTime.tm_hour = sysTime.wHour;
tmFileTime.tm_min = sysTime.wMinute;
tmFileTime.tm_sec = sysTime.wSecond;
return mktime( &tmFileTime );
3.2 遍历文件夹中所有的日志文件,清理若干天之前的文件
假定我们要清理7天前的日志文件,时间差值定为:
#define LOG_DELETE_INTERVAL_SECOND (7*24*60*60) // 删除7天之前的日志文件
我们去遍历文件夹中的所有日志文件(我们假定该文件夹中存放的都是日志文件,没有其他类型的文件),获取每个日志文件的最后修改时间,然后和当前的时间(调用time函数获取)做差值,如果大于差值宏LOG_DELETE_INTERVAL_SECOND的值,就将之删除掉。相关代码如下:
void DeleteLogFile( LPCTSTR strLogPath )
if ( !PathFileExists( strLogPath ) )
return;
time_t tCurTime = time( NULL ); // 获取当前时间
tstring strFindFileName = strLogPath;
strFindFileName += _T("\\\\*.*");
WIN32_FIND_DATA wfd;
HANDLE hFindFile = FindFirstFile( strFindFileName.c_str(), &wfd );
if ( hFindFile == INVALID_HANDLE_VALUE )
return;
while ( true )
if ( wfd.cFileName[0] != _T('.') )
// 非本级或上级目录
if ( wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) // 目录
if ( !FindNextFile( hFindFile, &wfd ) )
break;
continue;
else if ( wfd.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM ) // 系统文件,不处理
if ( !FindNextFile( hFindFile, &wfd ) )
break;
continue;
else // 用户日志文件
tstring strLogFile = strLogPath;
strLogFile += _T("\\\\");
strLogFile += wfd.cFileName;
time_t tModifyTime = GetFileModifyTime( strLogFile.c_str() );
// 如果是指定时间之前的文件,则将之删除掉(拿当前时间和文件的最后修改时间作比较)
if ( tCurTime - tModifyTime > DELETE_INTERVAL_SECOND )
DeleteFile( strLogFile.c_str() );
if ( !FindNextFile( hFindFile, &wfd ) )
break;
;
FindClose( hFindFile );
如果文件夹中包含有子文件夹,则需要修改上面的代码,改成递归遍历文件夹的逻辑即可。
以上是关于VC++获取文件的修改时间,定期清理若干天之前的日志文件(附源码)的主要内容,如果未能解决你的问题,请参考以下文章