简单实现日志保存, 支持设置日志文件数量, 单个日志文件大小上限, 自动超时保存日志, 日志缓存超限保存
CLogUtils.h
#pragma once
#include <string>
#include <windows.h>
#include <vector>
#include <map>
#include <mutex>
#include <tchar.h>
#include <thread>
#ifdef _UNICODE
using _tstring = std::wstring;
#else
using _tstring = std::string;
#endif
namespace CLogUtils
{
#define HISTORY_FILE_MAX_COUNT (16) //最多日志文件历史数量
#define AUTO_SAVE_TIME_OUT (1000 * 60) //自动保存超时时间(毫秒)
#define LOG_FILE_MAX_SIZE (1024 * 1024 * 4) //单个日志文件大小阈值(字节)
#define LOG_BUF_MAX_COUNT (1000) //日志缓冲大小阈值
#define LOG_INFO(format, ...)\
global_logger.Logging(_T(" INFO"), _T(__FILE__), _T(__FUNCTION__), __LINE__, format, ##__VA_ARGS__);
#define LOG_DEBUG(format, ...)\
global_logger.Logging(_T("DEBUG"), _T(__FILE__), _T(__FUNCTION__), __LINE__, format, ##__VA_ARGS__);
#define LOG_WARN(format, ...)\
global_logger.Logging(_T(" WARN"), _T(__FILE__), _T(__FUNCTION__), __LINE__, format, ##__VA_ARGS__);
#define LOG_ERROR(format, ...)\
global_logger.Logging(_T("ERROR"), _T(__FILE__), _T(__FUNCTION__), __LINE__, format, ##__VA_ARGS__);
class CLogHelper
{
public:
#define LogInfo(format, ...)\
Logging(_T(" INFO"), _T(__FILE__), _T(__FUNCTION__), __LINE__, format, ##__VA_ARGS__);
#define LogDebug(format, ...)\
Logging(_T("DEBUG"), _T(__FILE__), _T(__FUNCTION__), __LINE__, format, ##__VA_ARGS__);
#define LogWarn(format, ...)\
Logging(_T(" WARN"), _T(__FILE__), _T(__FUNCTION__), __LINE__, format, ##__VA_ARGS__);
#define LogError(format, ...)\
Logging(_T("ERROR"), _T(__FILE__), _T(__FUNCTION__), __LINE__, format, ##__VA_ARGS__);
public:
//
// @brief: 构造
// @param: nFileSize 文件大小阈值(字节)
// @param: nTmpCount 缓存条目阈值
// @param: nIntervalTime 自动存储时间间隔(毫秒)
// @ret: void
CLogHelper(
const _tstring& strDir = _T(""),
const _tstring& strName = _T(""),
DWORD nFileSize = LOG_FILE_MAX_SIZE,
DWORD nTmpCount = LOG_BUF_MAX_COUNT,
DWORD nIntervalTime = AUTO_SAVE_TIME_OUT
);
//删除拷贝构造与赋值重载
CLogHelper(const CLogHelper&) = delete;
CLogHelper& operator = (const CLogHelper&) = delete;
~CLogHelper();
//
// @brief: 记录一条日志
// @param: pstrLevel 日志等级
// @param: pstrFile 源码文件
// @param: pstrFunc 源码函数
// @param: nLine 行数
// @param: pstrFormat 格式化字符串
// @param: ... 可变参数
// @ret: void
void Logging(
LPCTSTR pstrLevel,
LPCTSTR pstrFile,
LPCTSTR pstrFunc,
UINT nLine,
LPCTSTR pstrFormat,
...
);
//
// @brief: 清空已经存储的日志文件
// @ret: void
void Clear();
//
// @brief: 格式化字符串
// @param: void
// @ret: bool 执行结果
_tstring Format(LPCTSTR pstrFormat, ...);
//
// @brief: 获取目录下文件路径
// @ret: std::vector<_tstring> 日志文件列表
std::map<int64_t, _tstring> GetLogFileList(const _tstring& strDir);
//
// @brief: 获取当前进程完全路径
// @ret: 当前进程完全路径 如 D:\Software\HxDPortableSetup.exe
static _tstring GetCurrentModulePath();
//
// @brief: 获取当前进程所在目录
// @ret: 当前进程所在目录 如 D:\Software
static _tstring GetCurrentModuleDir();
//
// @brief: 获取当前进程名
// @ret: 当前进程名 如 HxDPortableSetup.exe
static _tstring GetCurrentModuleName(bool bHasExt = false);
//
// @brief: 获取文件所在文件夹
// @param: strPath 文件名, 如: D:\Software\HxDPortableSetup.exe
// @ret: 文件夹 如 D:\Software
static _tstring GetFileDir(const _tstring& strPath);
//
// @brief: 获取文件名
// @param: strPath 文件名, 如: D:\Software\HxDPortableSetup.exe
// @param: bHasExt 是否包含扩展名
// @ret: 文件夹 如 HxDPortableSetup
static _tstring GetFileName(const _tstring& strPath, bool bHasExt = false);
//
// @brief: 检查文件是否存在
// @param: strPath 文件名, 如: D:\Software\HxDPortableSetup.exe
// @ret: 是否存在 存在返回 true
static bool IsArchive(const _tstring& strPath);
//
// @brief: 检查文件是否存在
// @param: strPath 文件名, 如: D:\Software\HxDPortableSetup.exe
// @ret: 是否存在 存在返回 true
static bool IsDirectory(const _tstring& strPath);
//
// @brief: 创建目录(递归)
// @param: strPath 路径
// @ret: 成功返回true
static bool CreateDir(const _tstring& strPath);
//
// @brief: 删除文件
// @param: strPath 路径
// @ret: 成功返回true
static bool DeleteArchive(const _tstring& strPath);
//
// @brief: 获取当前时间戳字符串
// @param: void
// @ret: _tstring 时间戳字符串 如: 2023-10-11 17:43:00.617
static _tstring GetCurrentTimeString();
//
// @brief: 获取当前日期字符串
// @param: void
// @ret: _tstring 时间戳字符串 如: 2023-10-11
static _tstring GetCurrentDateString();
//
// @brief: 获取当前时间戳
// @param: void
// @ret: 时间戳(单位: 毫秒) 如: 1697017380617
static int64_t GetCurrentTimestamp();
//
// @brief: 时间戳转字符串
// @param: strFormat 格式化字符串 如: "%04d-%02d-%02d %02d:%02d:%02d.%d"
// @param: timestamp 时间戳 如: 1697017380617
// @ret: 时间字符串 如: 2023-10-11 17:43:00.617
static _tstring TimestampToString(
const _tstring& strFormat = _T("%04d-%02d-%02d %02d:%02d:%02d.%d"),
int64_t timestamp = 0
);
//
// @brief: 获取文件大小
// @param: strPath 路径
// @ret: 文件大小
unsigned long long GetFileSize(const _tstring& strPath);
private:
//
// @brief: 调整日志文件数量
// @param: void
// @ret: void
void AdjustLogFile();
//
// @brief: 初始化
// @param: void
// @ret: bool 执行结果
bool Initialize();
//
// @brief: 取消初始化
// @param: void
// @ret: void
void Uninitialize();
//
// @brief: 初始化日志文件
// @param: void
// @ret: int 日志文件索引
void InitLogFile();
//
// @brief: 生成日志转储文件路径
// @param: void
// @ret: void
void GenerateLogFilePath();
//
// @brief: 输出日志到文件
// @ret: bool 执行结果
bool OutputToFile();
private:
LPTSTR m_lpBuf = nullptr; //格式化字符串使用的缓冲指针
std::mutex m_Lock; //线程安全锁
std::vector<_tstring> m_logList; //日志记录
std::map<int64_t, _tstring> m_logFileList; //日志文件记录, 按照时间戳排序
std::thread m_threadAutoSave; //自动保存线程对象
HANDLE m_hEvent = nullptr; //通知事件, 使用自动转储的超时等待
HANDLE m_hFile = INVALID_HANDLE_VALUE; //文件句柄, 日志文件写入使用
int64_t m_nFileTimetamp = 0; //日志文件时间戳
_tstring m_strSaveDir; //日志存放目录
_tstring m_strSaveName; //日志文件名
_tstring m_strFilePath; //当前日志文件路径
bool m_bStop = false; //停止标记
bool m_bFirst = false; //首次记录日志标记
DWORD m_MaxFileSize = 0; //文件大小阈值(到达阈值则转储到文件)
DWORD m_MaxTempCount = 0; //缓存条目阈值(到达阈值则转储到文件)
DWORD m_AutoSaveTime = 0; //自动保存间隔时间阈值(到达阈值则转储到文件)
DWORD m_LogTotalSize = 0; //日志文件统计
DWORD m_NextItemSize = 0; //下一条目日志大小
};
extern CLogHelper global_logger; //全局静态实例
}
CLogUtils.cpp
#include "CLogUtils.h"
#include <strsafe.h>
#include <tchar.h>
namespace CLogUtils
{
#define FORMAT_BUFFER_CH_SIZE (1024 * 4) //字符串格式化字符缓冲大小(字符)
//全局实例构造
CLogHelper global_logger(
_T(""),
CLogHelper::GetCurrentModuleName(true) + _T("_global"),
LOG_FILE_MAX_SIZE,
LOG_BUF_MAX_COUNT,
AUTO_SAVE_TIME_OUT
);
CLogHelper::CLogHelper(
const _tstring& strDir/* = _T("")*/,
const _tstring& strName/* = _T("")*/,
DWORD nFileSize/* = 1024 * 1024*/,
DWORD nTmpCount/* = 100*/,
DWORD nIntervalTime/* = 60*/
) :
m_strSaveDir(strDir),
m_strSaveName(strName),
m_MaxFileSize(nFileSize),
m_MaxTempCount(nTmpCount),
m_AutoSaveTime(nIntervalTime)
{
if (m_MaxFileSize < LOG_FILE_MAX_SIZE)
{
m_MaxFileSize = LOG_FILE_MAX_SIZE;
}
if (m_AutoSaveTime < AUTO_SAVE_TIME_OUT)
{
m_AutoSaveTime = AUTO_SAVE_TIME_OUT;
}
//默认目录为当前进程目录
if (m_strSaveDir.empty())
{
m_strSaveDir = GetCurrentModuleDir();
}
//默认文件名为当前进程名
if (m_strSaveName.empty())
{
m_strSaveName = GetCurrentModuleName(true);
}
//目录不存在就创建目录
if (!IsDirectory(m_strSaveDir))
{
CreateDir(m_strSaveDir);
}
this->Initialize();
}
CLogHelper::~CLogHelper()
{
this->Uninitialize();
}
bool CLogHelper::Initialize()
{
if (nullptr == m_lpBuf)
{
m_lpBuf = (LPTSTR)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, FORMAT_BUFFER_CH_SIZE * sizeof(TCHAR));
}
if (nullptr == m_hEvent)
{
m_hEvent = ::CreateEvent(nullptr, false, false, nullptr);
}
//开启一个线程进行自动保存
m_threadAutoSave = std::move(
std::thread([this]()
{
//超时或者退出时转储日志到文件
while (!m_bStop)
{
DWORD dwWait = ::WaitForSingleObject(m_hEvent, m_AutoSaveTime);
switch (dwWait)
{
case WAIT_TIMEOUT:
case WAIT_OBJECT_0:
{
std::lock_guard<std::mutex> lock(m_Lock);
this->OutputToFile();
m_logList.clear();
}
break;
default:
break;
}
}
}
)
);
return nullptr != m_lpBuf;
}
void CLogHelper::Uninitialize()
{
if (nullptr != m_lpBuf)
{
::HeapFree(::GetProcessHeap(), 0, m_lpBuf);
m_lpBuf = nullptr;
}
if (nullptr != m_hEvent)
{
m_bStop = true;
::SetEvent(m_hEvent);
}
if (m_threadAutoSave.joinable())
{
m_threadAutoSave.join();
}
if (INVALID_HANDLE_VALUE != m_hFile)
{
::CloseHandle(m_hFile);
m_hFile = INVALID_HANDLE_VALUE;
}
}
void CLogHelper::Logging(
LPCTSTR pstrLevel,
LPCTSTR pstrFile,
LPCTSTR pstrFunc,
UINT nLine,
LPCTSTR pstrFormat,
...
)
{
if (nullptr == m_lpBuf)
{
return;
}
DWORD dwTid = ::GetCurrentThreadId();
_tstring strLogContent = Format(_T("[%s] [%s] [%0.8X(%d)] [%s : %d] [%s] "),
GetCurrentTimeString().c_str(),
pstrLevel,
dwTid,
dwTid,
pstrFile,
nLine,
pstrFunc
);
//格式化日志内容
if (nullptr != m_lpBuf)
{
int nSize = 0;
va_list args;
va_start(args, pstrFormat);
nSize = _vsntprintf_s(m_lpBuf, FORMAT_BUFFER_CH_SIZE, _TRUNCATE, pstrFormat, args);
va_end(args);
}
//获取单行日志内容 + 固定前缀内容 + 真实内容
strLogContent += m_lpBuf;
strLogContent += _T("\r\n");
m_NextItemSize = (DWORD)(strLogContent.size() * sizeof(TCHAR));
std::lock_guard<std::mutex> lock(m_Lock);
//首次启动时, 重置大小统计
if (!m_bFirst)
{
InitLogFile();
AdjustLogFile();
m_LogTotalSize = (DWORD)GetFileSize(m_strFilePath);
m_bFirst = true;
}
//单个日志文件大小即将达到或超过阈值则输出到文件, 启用新的文件存储
if ((m_LogTotalSize + m_NextItemSize) >= m_MaxFileSize)
{
OutputToFile();
m_logList.clear();
::CloseHandle(m_hFile);
m_hFile = INVALID_HANDLE_VALUE;
(void)GenerateLogFilePath();
m_LogTotalSize = (DWORD)GetFileSize(m_strFilePath);
AdjustLogFile();
}
//已缓存条目达到阈值则输出到文件
else if (m_logList.size() >= m_MaxTempCount)
{
OutputToFile();
m_logList.clear();
}
//累加统计单个日志文件大小
m_LogTotalSize += m_NextItemSize;
//缓存日志
m_logList.emplace_back(strLogContent);
return;
}
void CLogHelper::Clear()
{
std::lock_guard<std::mutex> lock(m_Lock);
if (INVALID_HANDLE_VALUE != m_hFile)
{
::CloseHandle(m_hFile);
m_hFile = INVALID_HANDLE_VALUE;
}
m_logFileList = GetLogFileList(m_strSaveDir);
for (const auto& item: m_logFileList)
{
DeleteArchive(item.second);
}
m_logFileList.clear();
}
void CLogHelper::AdjustLogFile()
{
//检查文件数量是否到达阈值, 到达的话删除前面的文件
if (m_logFileList.size() > HISTORY_FILE_MAX_COUNT)
{
size_t nDeleteCount = m_logFileList.size() - HISTORY_FILE_MAX_COUNT;
size_t nIndex = 0;
//删除多出的文件
for (const auto& item : m_logFileList)
{
DeleteArchive(item.second);
nIndex++;
if (nIndex >= nDeleteCount)
{
break;
}
}
//文件名整体向前移动
_tstring lastPath;
for (const auto& item : m_logFileList)
{
if (lastPath.empty())
{
::MoveFileEx(item.second.c_str(), lastPath.c_str(), MOVEFILE_DELAY_UNTIL_REBOOT);
}
lastPath = item.second;
}
//从日志文件记录列表中删除
for (size_t i = 0; i < nDeleteCount; i++)
{
m_logFileList.erase(m_logFileList.begin());
}
}
}
void CLogHelper::InitLogFile()
{
//如果上次最后一个日志文件大小还能存储日志, 就沿用上次的日志文件
m_logFileList = GetLogFileList(m_strSaveDir);
if (!m_logFileList.empty())
{
auto itLast = m_logFileList.end();
itLast--;
m_nFileTimetamp = itLast->first;
m_strFilePath = itLast->second;
//上次最后一个日志文件不能存储更多日志, 则生成新的日志文件路径
unsigned long long ullFileSize = (DWORD)GetFileSize(m_strFilePath);
if ((ullFileSize + m_NextItemSize) >= m_MaxFileSize)
{
(void)GenerateLogFilePath();
}
}
else
{
(void)GenerateLogFilePath();
}
}
void CLogHelper::GenerateLogFilePath()
{
//得到日志文件时间戳
m_nFileTimetamp = GetCurrentTimestamp();
//得到日志文件路径
m_strFilePath = Format(_T("%s\\%s_%s.log"),
m_strSaveDir.c_str(),
m_strSaveName.c_str(),
TimestampToString(
_T("%04d-%02d-%02d_%02d-%02d-%02d-%03d"),
m_nFileTimetamp).c_str()
);
//创建一下文件(防止在资源管理器中看不到新的日志文件)
m_hFile = CreateFile(m_strFilePath.c_str(),
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
//在文件末尾追加内容
LARGE_INTEGER liDistanceToMove = { 0 };
::SetFilePointerEx(m_hFile, liDistanceToMove, NULL, FILE_END);
m_logFileList.insert(std::make_pair(m_nFileTimetamp, m_strFilePath));
}
std::map<int64_t, _tstring> CLogHelper::GetLogFileList(const _tstring& strDir)
{
std::map<int64_t, _tstring> fileList;
WIN32_FIND_DATA findData = { 0 };
HANDLE hFindHandle = INVALID_HANDLE_VALUE;
hFindHandle = FindFirstFile((strDir + _T("\\*.*")).c_str(), &findData);
if (INVALID_HANDLE_VALUE == hFindHandle)
{
return fileList;
}
do
{
_tstring strName = findData.cFileName;
//非目录
if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
//检查输入规则
int nConverted = 0;
SYSTEMTIME st = { 0 };
_tstring strPath = strDir + _T("\\") + strName;
_tstring strPrefix = Format(_T("%s_%%4hd-%%2hd-%%2hd_%%2hd-%%2hd-%%2hd-%%3hd.log"), m_strSaveName.c_str());
nConverted = _stscanf_s(findData.cFileName, strPrefix.c_str(),
&st.wYear, &st.wMonth, &st.wDay, &st.wHour,
&st.wMinute, &st.wSecond, &st.wMilliseconds);
//检查文件名规则是否符合要求
if (7 == nConverted)
{
FILETIME ftFile = { 0 };
FILETIME ftLocal = { 0 };
int64_t timestamp = 0;
::SystemTimeToFileTime(&st, &ftLocal);
::LocalFileTimeToFileTime(&ftLocal, &ftFile);
timestamp = ((int64_t)ftFile.dwHighDateTime << 32) | ftFile.dwLowDateTime;
timestamp = (timestamp - 116444736000000000) / 10000;
fileList.insert(std::make_pair(timestamp, strPath));
}
}
//上一级目录与当前目录跳过
if (0 == _tcscmp(findData.cFileName, _T(".")) || 0 == _tcscmp(findData.cFileName, _T("..")))
{
continue;
}
} while (::FindNextFile(hFindHandle, &findData));
::FindClose(hFindHandle);
return fileList;
}
bool CLogHelper::OutputToFile()
{
bool bSuccess = false;
//没有需要写入的日志
if (m_logList.empty())
{
return true;
}
if (INVALID_HANDLE_VALUE == m_hFile)
{
return false;
}
//写入日志
DWORD dwNumberOfBytesWrite = 0;
for (const auto& item : m_logList)
{
bSuccess = ::WriteFile(m_hFile, item.c_str(), (DWORD)(item.size() * sizeof(TCHAR)), &dwNumberOfBytesWrite, NULL);
if (!bSuccess)
{
break;
}
}
return bSuccess;
}
_tstring CLogHelper::Format(LPCTSTR pstrFormat, ...)
{
_tstring strResult;
if (nullptr != m_lpBuf)
{
int nSize = 0;
va_list args;
va_start(args, pstrFormat);
nSize = _vsntprintf_s(m_lpBuf, FORMAT_BUFFER_CH_SIZE, _TRUNCATE, pstrFormat, args);
va_end(args);
strResult = m_lpBuf;
}
return strResult;
}
_tstring CLogHelper::GetCurrentTimeString()
{
TCHAR szBuf[MAX_PATH] = { 0 };
SYSTEMTIME st = { 0 };
(void)::GetLocalTime(&st);
::StringCchPrintf(szBuf, _countof(szBuf),
_T("%04d-%02d-%02d %02d:%02d:%02d.%d"),
st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds
);
return szBuf;
}
_tstring CLogHelper::GetCurrentDateString()
{
TCHAR szBuf[MAX_PATH] = { 0 };
SYSTEMTIME st = { 0 };
(void)::GetLocalTime(&st);
::StringCchPrintf(szBuf, _countof(szBuf), _T("%04d-%02d-%02d"), st.wYear, st.wMonth, st.wDay);
return szBuf;
}
int64_t CLogHelper::GetCurrentTimestamp()
{
int64_t timeStamp = 0;
(void)::GetSystemTimeAsFileTime((FILETIME*)&timeStamp);
return (timeStamp - 116444736000000000) / 10000;
}
_tstring CLogHelper::TimestampToString(const _tstring& strFormat, int64_t timestamp)
{
TCHAR szBuf[MAX_PATH] = { 0 };
SYSTEMTIME st = { 0 };
FILETIME ftFile = { 0 };
FILETIME ftLocal = { 0 };
timestamp = timestamp * 10000 + 116444736000000000;
ftFile.dwLowDateTime = timestamp & 0xFFFFFFFF;
ftFile.dwHighDateTime = timestamp >> 32;
::FileTimeToLocalFileTime(&ftFile, &ftLocal);
::FileTimeToSystemTime(&ftLocal, &st);
::StringCchPrintf(szBuf, _countof(szBuf),
strFormat.c_str(),
st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds
);
return szBuf;
}
_tstring CLogHelper::GetCurrentModulePath()
{
TCHAR szCurPath[MAX_PATH] = { 0 };
::GetModuleFileName(NULL, szCurPath, _countof(szCurPath));
_tstring strResult = szCurPath;
return strResult;
}
_tstring CLogHelper::GetCurrentModuleDir()
{
return GetFileDir(GetCurrentModulePath());
}
_tstring CLogHelper::GetCurrentModuleName(bool bHasExt/* = true*/)
{
return GetFileName(GetCurrentModulePath(), bHasExt);
}
_tstring CLogHelper::GetFileDir(const _tstring& strPath)
{
_tstring strResult;
size_t nIndex = strPath.find_last_of(_T('\\'));
if (nIndex != _tstring::npos)
{
strResult = strPath.substr(0, nIndex);
}
return strResult;
}
_tstring CLogHelper::GetFileName(const _tstring& strPath, bool bHasExt/* = true*/)
{
_tstring strResult = strPath;
size_t nIndex = strResult.find_last_of(_T('\\'));
if (nIndex != _tstring::npos)
{
strResult = strResult.substr(nIndex + 1);
}
if (!bHasExt)
{
nIndex = strResult.find_last_of(_T('.'));
if (nIndex != _tstring::npos)
{
return strResult.substr(0, nIndex);
}
}
return strResult;
}
bool CLogHelper::IsArchive(const _tstring& strPath)
{
WIN32_FILE_ATTRIBUTE_DATA attr = { 0 };
if (!::GetFileAttributesEx(strPath.c_str(), GetFileExInfoStandard, &attr))
{
return false;
}
return attr.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE;
}
bool CLogHelper::IsDirectory(const _tstring& strPath)
{
WIN32_FILE_ATTRIBUTE_DATA attr = { 0 };
if (!::GetFileAttributesEx(strPath.c_str(), GetFileExInfoStandard, &attr))
{
return false;
}
return attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
}
bool CLogHelper::CreateDir(const _tstring& strPath)
{
_tstring strDriver; //驱动器号, 如 D:
_tstring strSubPath = strPath; //路径, 如 Test\1\2\3
if (strPath.empty())
{
return false;
}
//获取盘符
do
{
size_t nFindIndex = strPath.find_first_of(':'); //检查是否有驱动器号
if (nFindIndex == _tstring::npos)
{
break;
}
strDriver = strPath.substr(0, nFindIndex + 1); //得到驱动器号, 如 D:
nFindIndex = strPath.find(_T("\\"), nFindIndex);
if (nFindIndex == _tstring::npos)
{
break;
}
strSubPath = strPath.substr(nFindIndex + 1); //得到路径, 如 Test\1\2\3
} while (false);
_tstring strDestDir;
size_t nFindBegin = 0;
size_t nFindIndex = 0;
do
{
nFindIndex = strSubPath.find(_T("\\"), nFindBegin);
if (nFindIndex != _tstring::npos)
{
strDestDir = strSubPath.substr(0, nFindIndex);
nFindBegin = nFindIndex + 1;
}
else
{
strDestDir = strSubPath;
}
if (!strDriver.empty())
{
strDestDir = strDriver + _T("\\") + strDestDir;
}
if (!::CreateDirectory(strDestDir.c_str(), NULL) && ERROR_ALREADY_EXISTS != ::GetLastError())
{
return false;
}
} while (nFindIndex != _tstring::npos);
return true;
}
bool CLogHelper::DeleteArchive(const _tstring& strPath)
{
if (strPath.empty())
{
return false;
}
return ::DeleteFile(strPath.c_str());
}
unsigned long long CLogHelper::GetFileSize(const _tstring& strPath)
{
unsigned long long ullSize = 0;
WIN32_FILE_ATTRIBUTE_DATA attr = { 0 };
if (!::GetFileAttributesEx(strPath.c_str(), GetFileExInfoStandard, &attr))
{
return 0;
}
ullSize = (unsigned long long)attr.nFileSizeHigh << 32 | attr.nFileSizeLow;
return ullSize;
}
}
使用
main.cpp
#include <iostream>
#include "CLogUtils.h"
#include <tchar.h>
int _tmain(int argc, LPCTSTR argv[])
{
while (true)
{
uint64_t uBegin = CLogUtils::CLogHelper::GetCurrentTimestamp();
uint64_t uEnd = 0;
int nCount = 10000;
std::cout << " CurrentTimestamp: " << uBegin << std::endl;
for (int i = 0; i < nCount; i++)
{
CLogUtils::LOG_INFO(_T("%d %s"), 1024, _T("FlameCyclone"));
}
uEnd = CLogUtils::CLogHelper::GetCurrentTimestamp();
std::cout << "Repeat " << nCount << " Cost time: " << uEnd - uBegin << std::endl;
system("pause");
}
return 0;
}
x64 Debug效果: