《VC++实战》之定期删除旧的日志文件(过期日志文件)

1 背景

实际项目中经常遇到需要将程序产生的“垃圾文件”定期进行删除,避免占用储存空间。诸如程序输出的日志文件、缩略图、缓存影片数据等。

2 情景

这里假设一种情景:某大型软件在实际生产过程中,会产生日志文件到指定的日志存放路径log下,并且产生日志的文件后缀为.log,需要程序检查此目录下创建时间超过指定期限的过期文件。

3 实现

  • 开发环境:Visual Studio 2013
  • 字符集:使用Unicode字符集

实现方式有很多种,这里使用多线程的方式来实现。

3.1 头文件

包含_beginthreadex()使用的头文件和std::string使用的头文件。

#include <process.h>
#include <string>

声明

public:
    static unsigned int WINAPI DeleteExpireDirectoryThread(LPVOID lpvoid);

private:
    std::string savePath;
    int saveDays;

3.2 源文件

创建线程

    HANDLE hDelDirHand;
    hDelDirHand = (HANDLE)_beginthreadex(NULL, 0, DeleteExpireDirectoryThread, this, 0, NULL);
    CloseHandle(hDelDirHand);

线程操作

unsigned int WINAPI AppLogging::DeleteExpireDirectoryThread(LPVOID lpvoid)
{
	AppLogging* pThis = (AppLogging*)lpvoid;

	int nDays = pThis->saveDays;
	std::string logPath = pThis->savePath;

	while (1)
	{
		WIN32_FIND_DATAA findData;
		ZeroMemory(&findData, sizeof(WIN32_FIND_DATAA));
		HANDLE hError;

		char FilePathName[255];
		std::string logPathAll = logPath + "\\*.*";

		hError = FindFirstFileA(logPathAll.c_str(), (LPWIN32_FIND_DATAA)&findData);
		if (hError == INVALID_HANDLE_VALUE)
		{
			Sleep(5000);
			continue;
		}
		while (::FindNextFileA(hError, (LPWIN32_FIND_DATAA)&findData))
		{
			// 过虑.和..
			if (strcmp(findData.cFileName, ".") == 0
				|| strcmp(findData.cFileName, "..") == 0)
			{
				continue;
			}
			
			std::string tempFileName = findData.cFileName;
			std::size_t found = tempFileName.find(".log");
			if (found == std::string::npos) //不是日志文件
			{
				continue;
			}

			tempFileName = logPath + "\\" + tempFileName;
			FILETIME ftCreate, ftModify, ftAccess;
			std::string strCreateTime, strModifyTime, strAccessTime;

			HANDLE hFile = CreateFileA(tempFileName.c_str(), GENERIC_READ,          // open for reading
				FILE_SHARE_READ,       // share for reading
				NULL,                            // default security
				OPEN_EXISTING,          // existing file only
				FILE_FLAG_BACKUP_SEMANTICS, // normal file
				NULL);

			if (!GetFileTime(hFile, &ftCreate, &ftAccess, &ftModify))
			{
				CloseHandle(hFile);
				continue;
			}
			CloseHandle(hFile);

			//文件时间转为系统时间
			SYSTEMTIME createTime;
			ZeroMemory(&createTime, sizeof(SYSTEMTIME));
			FileTimeToSystemTime(&ftCreate, &createTime);
			//获取当前时间
			SYSTEMTIME stSystem;
			::GetSystemTime(&stSystem);

			int diffDays = GetDiffDays(createTime, stSystem);
			if (GetDiffDays(createTime, stSystem) > nDays) //该日志文件过期
			{
				DeleteFileA(tempFileName.c_str()); //删除过期日志文件
			}
		}

		Sleep(10000);
	}

	return 0;
}

时间大小比较

time_t FileTimeToTime_t(const FILETIME &ft)
{
	ULARGE_INTEGER ui;
	ui.LowPart = ft.dwLowDateTime;
	ui.HighPart = ft.dwHighDateTime;
	return ((LONGLONG)(ui.QuadPart - 116444736000000000) / 10000000);
}

int GetDiffSeconds(const SYSTEMTIME &t1, const SYSTEMTIME &t2)
{
	FILETIME fTime1 = { 0, 0 };
	FILETIME fTime2 = { 0, 0 };
	SystemTimeToFileTime(&t1, &fTime1);
	SystemTimeToFileTime(&t2, &fTime2);

	time_t tt1 = FileTimeToTime_t(fTime1);
	time_t tt2 = FileTimeToTime_t(fTime2);

	return (int)(tt2 - tt1);
}

int GetDiffDays(const SYSTEMTIME &t1, const SYSTEMTIME &t2)
{
	int diffSeconds = GetDiffSeconds(t1, t2);
	return diffSeconds / (24 * 3600);
}

 

;