日志的重要性不言而喻,是帮助我们快速定位bug的利器,必须自己学会利用,有了下面这个例子,想怎么封装就怎么封装。当然,最好将这些封装成类里面的函数,然后用单例的管理器来管理,简单基本的日志系统就可以在此基础上构思出来了。下面是win32下日志代码,注释比较详细,相信最新的新手也完全能懂。
// LogTest.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <Windows.h>
#include <iostream>
#include "shlwapi.h"
//using namespace std;
#include <string>
//确保文件夹存在
bool ensureDirectory(std::string path){
WIN32_FIND_DATAA FindFileData;//文件的属性
HANDLE hFind;
hFind = FindFirstFileA(path.data(), &FindFileData);//找到文件夹句柄并储存信息
//如果没有则创建该目录文件夹
if (hFind == INVALID_HANDLE_VALUE) {
::CreateDirectoryA(path.data(), NULL);
}
::FindClose(hFind);
return true;
}
int _tmain(int argc, _TCHAR* argv[])
{
bool isNewLogFile = false;
//根据年月日创建不同时间日志,有的程序可能长期运行很多天,那就需要将文件夹细分,而不是都写在同一个日志文件里面
int m_nOldYear=-1;
int m_nOldMonth=-1;
int m_nOldDay=-1;
FILE* m_pFile=NULL;//文件句柄
int m_curFileSize=0;//记录日志当前文件大小
const int m_nFileMaxSize=10*1000*1000;//日志文件不应该太累赘,最好轻量级
volatile int m_serialNum=0;//目录列,前面这个修饰表示编译器读取值的时候每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份
bool bOutConsole = false;//是否需要控制台提示,这里不要控制台弹出提示
SYSTEMTIME sys; //用于存储系统时间结构体
GetLocalTime( &sys ); //调用windows API存储系统时间
char chDateTime[255] = {0};
//将时间转换为字符串用于格式化输出
sprintf(chDateTime,"%4d-%02d-%02d %02d:%02d:%02d",sys.wYear,sys.wMonth,sys.wDay,sys.wHour,sys.wMinute, sys.wSecond);
std::string strLog = chDateTime;//写入日志的内容
char szFolderPath[MAX_PATH + 1] = {0};
GetCurrentDirectoryA(MAX_PATH,szFolderPath);//获取当前文件夹路径并保存至szFolderPath
std::string m_FolderName("\\log");//日志文件夹名字log
std::string m_curAbsolutePath =szFolderPath+ m_FolderName ;//整个日子文件夹路径
HANDLE m_mutex = ::CreateMutex(NULL, FALSE, NULL);//找出当前系统是否已经存在指定进程的实例。如果没有则创建一个互斥体。这里我们并没有用到,但是在多线程里面必须用到
std::string currPath = m_curAbsolutePath;
//确认当前目录
ensureDirectory(currPath);
//按照时间确认对应目录是否存在
SYSTEMTIME localSystemDateTime;
GetLocalTime( &localSystemDateTime );
//确认年目录
char chYearTime[255] = {0};
sprintf(chYearTime,"\\%4d",localSystemDateTime.wYear);
currPath += chYearTime;
//
ensureDirectory(currPath);
//确认月目录
char chMonthTime[255] = {0};
sprintf(chMonthTime,"\\%02d",localSystemDateTime.wMonth);
currPath += chMonthTime;
ensureDirectory(currPath);
//确认日目录
char chDayTime[255] = {0};
sprintf(chDayTime,"\\%02d",localSystemDateTime.wDay);
currPath += chDayTime;
ensureDirectory(currPath);
if(localSystemDateTime.wYear!=m_nOldYear||localSystemDateTime.wMonth!=m_nOldMonth||localSystemDateTime.wDay!=m_nOldDay){
isNewLogFile = true;
m_nOldYear = localSystemDateTime.wYear;
m_nOldMonth = localSystemDateTime.wMonth;
m_nOldDay = localSystemDateTime.wDay;
}
//是否需要创建新的日志文件
if(NULL!=m_pFile)
{
if(isNewLogFile)
{
fflush(m_pFile);
fclose(m_pFile);
m_pFile = NULL;
m_curFileSize = 0;
}
else if(m_curFileSize>=m_nFileMaxSize)
{
if(NULL!=m_pFile)
{
fflush(m_pFile);
fclose(m_pFile);
m_pFile = NULL;
m_curFileSize = 0;
}
}
}
if(NULL==m_pFile){
m_serialNum++;
char chFile[255] = {0};
sprintf(chFile,"%02d_%02d_%02d_%d",localSystemDateTime.wHour,localSystemDateTime.wMinute, localSystemDateTime.wSecond, m_serialNum);
std::string acturaFileName = currPath + "\\" + std::string(chFile) +".log";
if(m_pFile){
fflush(m_pFile);
fclose(m_pFile);
}
//以写入的方式打开
m_pFile = fopen(acturaFileName.data(),"w+");
m_curFileSize = 0;
if(NULL==m_pFile){
int nError = ::GetLastError();
}
}
//以上对日志目录进行了一个较完善的规划,然后就是测试写入日志:
///
std::string strType ="日志类型:XXX";
std::string strValue = "日志值:***";
strLog += strType + strType;
strLog += "\r\n";
m_curFileSize += strLog.size();
if(m_pFile)
{
fwrite(strLog.data(), strLog.size(), 1, m_pFile);
if(bOutConsole)
{
std::cout << strLog;
}
fflush(m_pFile);//清除读写缓冲区,需要立即把输出缓冲区的数据进行物理写入时
}
return 0;
}
然后运行后会在相应的目录下产生一个这样的文件,日志内容也完全对应上。
这当然是最基本最简单的,但是再高的大厦也是这样的基础堆积而成。