线程安全的,应该还有bug欢迎反馈。
代码复制可以直接用
###Log.h
#pragma once
#include <fstream>
#include <mutex>
#include <vector>
//日志等级
//LEVEL>3 写入log
//LEVEL<=3 写入info
// LEVEL 0 1 2 3 4 5 6 7
enum EM_LEVEL{DBG=0,SYS,TCP,SQL,INF,WAR, ERR, OPT};
class CLog
{
private:
struct STRUCT_FILE //文件操作结构体
{
fstream f; //文件对象
std::string sFlash; //日志缓存
long t;//日志缓存清空时间节点 用于判断缓存是否距离上一次写入
long t_open;//文件打开时间节点
int ct_line;//缓存文件日志条数
};
STRUCT_FILE mf;
std::mutex mutex_file;//日志文件锁
CString csTargetDir;//文件存储根目录
CString csSuffix;//文件后缀名,比如 .txt
CString csSubDir;//日志文件所在文件夹
CString csFileName;//文件名 本类默认文件名是 _0
CString csFullWriteFilePath;//写入的文件绝对地址。包含文件名,后缀
CString csReadFilePath;//读取的文件绝对地址。包含文件名,后缀
CWinThread *pWriteThread;//写文件线程指针
CWinThread *pReadThread;//读文件线程指针
BOOL bThreadRun;//线程退出控制
public:
CLog(CString mTargetDir,CString mSubDir=_T(""),CString mSuffix=_T(".txt"));
~CLog(void);
private:
CLog(void);
static UINT ThreadWriteDataToFile(LPVOID lp);
static UINT ThreadReadDataFromFile(LPVOID lp);
void WriteFile();
CString GetFileDir();
CString GetFilePath();
BOOL OpenMyFile(CString mNewPath);
//BOOL SaveFile();
void WriteStringToFile();
std::vector<std::string> ReadFile();
public:
void StartWriteThread();
void StartReadThread(CString mfileName);
void MakeWriteText(std::string content,UINT mLevel,std::string sType, int line,const char* pFunction,std::string mTime,std::string userName);
};
###Log.cpp
//日志写入读取类
//2022年9月22日
//哑巴湖大水怪
#include "stdafx.h"
#include "MyTool.h"
#include "Log.h"
#define MAX_FILE_SIZE 10485760 //1024*1024*10 10m大小
#define DEG_OUT_LOG_LEVEL 0 //debug输出窗口输出等级上限(不包含)
#define WRITE_FLASH_DELAY_TIME 3000 //日志缓存每隔3秒写一次
//#define FILE_SAVE_DELAY 20 //20秒关闭再打开文件,保存数据
/***********************
*作用:构造函数
*参数:
*CString mTargetDir 目标文件夹 为空则默认放程序运行在根目录
*CString mSubDir 放日志文件的文件夹名字 为空则默认放程序运行在根目录
*CString mSuffix 文件后缀名
*****************************/
CLog::CLog(CString mTargetDir,CString mSubDir,CString mSuffix)
{
if (mTargetDir.GetLength()==0)
{
mTargetDir=CMyTool::GetExePath();
}
if (mSuffix.GetLength()==0)
{
mSuffix=_T(".txt");
}
csTargetDir=mTargetDir;
csSubDir=mSubDir;
csSuffix=mSuffix;
StartWriteThread();
}
CLog::CLog(void)
{
csTargetDir=CMyTool::GetExePath();
csSubDir=_T("");
csSuffix=_T(".txt");
StartWriteThread();
}
/***********************
*作用:在此关闭打开的文件,并等待写数据线程退出
*参数:
*
*****************************/
CLog::~CLog(void)
{
bThreadRun=FALSE;
if (pWriteThread)
{
WaitForSingleObject(pWriteThread->m_hThread,INFINITE);
}
if (pReadThread)
{
WaitForSingleObject(pReadThread->m_hThread,INFINITE);
}
if(mf.f.is_open())
{
std::lock_guard<std::mutex> lck(mutex_file);
mf.f.close();
mf.t_open=0;
}
TRACE("写入线程退出 文件%s 关闭 Log对象析构 \n",CMyTool::Wchar_tToChar_UnicodeToAnsi(csFullWriteFilePath).data());
}
/***********************
*作用:写数据线程
*参数:CLog * 指针
*
*****************************/
UINT CLog::ThreadWriteDataToFile(LPVOID lp)
{
CLog*p=(CLog*)lp;
p->WriteFile();
return 0;
}
/***********************
*作用:读数据线程
*参数:CLog * 指针
*
*****************************/
UINT CLog::ThreadReadDataFromFile(LPVOID lp)
{
CLog*p=(CLog*)lp;
p->ReadFile();
return 0;
}
/***********************
*作用:写数据函数
*参数:CLog * 指针
*
*****************************/
void CLog::WriteFile ()
{
while (bThreadRun)
{
CString cstr=GetFilePath();//重新计算文件绝对路径,如果文件大小大于 MAX_FILE_SIZE 就会换新的绝对路径
if (cstr!=csFullWriteFilePath)//新计算的和当前打开的不一致,说明日志文件大小超出定值或者日期变了
{
if(!OpenMyFile(cstr))//文件打开失败 不写入,直接跳过
{
Sleep(100);
continue;
}
}
if ((clock()-mf.t)>WRITE_FLASH_DELAY_TIME)//缓存日志字符串不够大情况下 WRITE_FLASH_DELAY_TIME ms写一次
{
WriteStringToFile();
}
if ((mf.sFlash.length())>(size_t)(MAX_FILE_SIZE*0.01))//缓存日志字符串超长,写入文件
{
WriteStringToFile();
}
/* if(!SaveFile())//20秒关闭一次并重新打开文件。
{
Sleep(1000);
continue;
}*/
Sleep(1000);//防止缓存区没数据或者日志文件打开失败空转CUP使用率飙升
}
WriteStringToFile();//程序正常退出之前将缓存的日志写入文件
}
/***********************
*作用:获取最终文件夹绝对路径
*参数:
* 返回 CString fileDir; 计算出的日志存放文件夹
*****************************/
CString CLog::GetFileDir()
{
_SYSTEMTIME st;
GetLocalTime(&st);
CString fileDir;
//按日期生成 月,日 文件夹 例:....Debug\log\2022-09\22\_0.log
//fileDir.Format(_T("%s%s%d-%02d\\%02d\\"),csTargetDir, csSubDir, st.wYear,st.wMonth,st.wDay);
//按日期生成日 文件夹 例:....Debug\log\2022-09-22\_0.log
//fileDir.Format(_T("%s%s%d-%02d-%02d\\"),csTargetDir, csSubDir, st.wYear,st.wMonth,st.wDay);
//按日期生成年 文件夹 例:....Debug\log\2022\09-22_0.log
fileDir.Format(_T("%s%s%d\\%02d-%02d"),csTargetDir, csSubDir, st.wYear,st.wMonth,st.wDay);
return fileDir;
}
/***********************
*作用:计算日志文件绝对路径,如果日志文件大小大于MAX_FILE_SIZE,则重新创建。
当天文件名则数字从0开始,数字越大存储的日志越新。
如果日期换了也重新创建日志文件
*参数:
* 返回 CString mFileFullPath; 计算出的新路径
*****************************/
CString CLog::GetFilePath()
{
CString sDir=GetFileDir();
CMyTool::IsDirExsit(sDir,csTargetDir.GetLength());//判断文件路径的文件夹是否存在,不存在就创建
CString mFileFullPath=sDir+_T("_0")+csSuffix;//起始日志文件绝对路径
int i = 1;
CFileStatus fileStatus;
while (true)
{
if (CFile::GetStatus(mFileFullPath, fileStatus))
{
if(fileStatus.m_size>MAX_FILE_SIZE)//当前日志文件过大,重新依次生成新文件绝对路径
{
mFileFullPath.Format(_T("%s_%d%s"),sDir,i++,csSuffix);
}else
{
break;
}
}else//获取文件大小失败 返回起始日志文件绝对路径,获取大小失败打开也会失败
{
break;
}
}
return mFileFullPath;
}
/*****************************
void open ( const char * filename,
ios_base::openmode mode = ios_base::in | ios_base::out );
void open(const wchar_t *_Filename,
ios_base::openmode mode= ios_base::in | ios_base::out,
int prot = ios_base::_Openprot);
ios::app: //以追加的方式打开文件
ios::ate: //文件打开后定位到文件尾,ios:app就包含有此属性
ios::binary: //以二进制方式打开文件,缺省的方式是文本方式。
ios::in: //文件以输入方式打开(文件数据输入到内存) 读文件
ios::out: //文件以输出方式打开(内存数据输出到文件) 写文件
ios::nocreate: //不建立文件,所以文件不存在时打开失败
ios::noreplace://不覆盖文件,所以打开文件时如果文件存在失败
ios::trunc: //如果文件存在,把文件长度设为0
打开文件的属性取值(prot ):
0:普通文件,打开访问
1:只读文件
2:隐含文件
4:系统文件
可以用“或”或者“+”把以上属性连接起来,如3或1|2就是以只读和隐含属性打开文件
**********************************/
/***********************
*作用:写的方式打开日志文件
*参数:
* 返回 BOOL TRUE 打开成功 ,FALSE 打开失败
*****************************/
BOOL CLog::OpenMyFile(CString mNewPath)
{
std::lock_guard<std::mutex> lck(mutex_file);
if(mf.f.is_open())
{
mf.t_open=0;
mf.f.close();
csFullWriteFilePath=_T("");
}
csFullWriteFilePath=mNewPath;
mf.f.open(mNewPath,ios::out|ios::app);
if(!mf.f.is_open())
{
mf.t_open=0;
TRACE("%s 文件未打开!e=%d\n",CMyTool::Wchar_tToChar_UnicodeToAnsi(csFullWriteFilePath).data(),GetLastError());
return FALSE;
}
mf.t_open=clock();
return TRUE;
}
/***********************
*作用:关闭当前文件并重新打开
*参数:
* 返回 BOOL TRUE 打开成功 ,FALSE 打开失败
*****************************/
//BOOL CLog::SaveFile()
//{
// if (mf.t_open!=0)//说明文件已打开
// {
// long t=clock()-mf.t_open;
// if (t>1000*1*FILE_SAVE_DELAY )
// {
// BOOL b=OpenMyFile(csFullWriteFilePath);
// TRACE("%s %d 返回值%d 时间间隔 %f \r\n",__FILE__,__LINE__,b,t*0.001);
// return b;
// }
// }
// return TRUE;
//}
/***********************
*作用:写文件操作
*参数:
* 返回
*****************************/
void CLog::WriteStringToFile()
{
if(!mf.f.is_open())//文件没打开
{
return;
}
if(mf.sFlash.length()==0)//缓冲日志字符串没数据
{
return;
}
long ts=clock();
int ml=mf.sFlash.length();
int mct=mf.ct_line;
std::lock_guard<std::mutex> lck(mutex_file);
mf.f.write(mf.sFlash.data(),mf.sFlash.length());
mf.sFlash="";
mf.ct_line=0;
mf.t=clock();//重置字符串生成时间节点
ts=clock()-ts;
TRACE("缓存字节 :%d 行数:%d 用时:%d ms \n",ml,mct,ts);
}
/***********************
*作用:启动写日志线程 ,在MyLog对象生成时候就启动,程序退出线程退出
*参数:
* 返回
*****************************/
void CLog::StartWriteThread()
{
bThreadRun=TRUE;
pWriteThread=AfxBeginThread(ThreadWriteDataToFile,(LPVOID)this,THREAD_PRIORITY_BELOW_NORMAL);
}
/***********************
*作用:启动读日志线程 调用 READLOG(p,filename) ,读完文件结束,内容存在vector里
*参数:
* 返回
*****************************/
void CLog::StartReadThread(CString mfileName)
{
bThreadRun=TRUE;
csReadFilePath=csFileName;
pReadThread=AfxBeginThread(ThreadReadDataFromFile,(LPVOID)this,THREAD_PRIORITY_BELOW_NORMAL);
}
/***********************
*作用:格式化日志内容
*参数:
*std::string content 日志主体内容
*UINT mLevel 日志等级
*std::string sType 日志类型
*int line 产生日志的代码行号
*const char* pFunction 产生日志的函数名称
*std::string mTime 产生日志时间
*std::string userName 登录人员用户名
* 返回
*****************************/
void CLog::MakeWriteText(std::string content,UINT mLevel,std::string sType,
int line,const char* pFunction,
std::string mTime,std::string userName/*=""*/)
{
std::string mstrLog="";
//mLevel>3 写入log
//mLevel<=3 写入info
//如果不份文件则去掉这里的判断。
if (mLevel>SQL)//写入 .log文件 //不需要记录行号,函数名
{
if (mLevel==OPT)//操作记录需要记录登录人员
{
mstrLog=MFT("%s%s%s,操作人:%s\n",mTime.data(),sType.data(),content.data(),userName.data());//换行符\r\n会每空一行写一条
}else
{
mstrLog=MFT("%s%s%s\n",mTime.data(),sType.data(),content.data());
}
}else if (mLevel<=mLevel&&mLevel>=0)//写入 .info文件 //包含记录行号,函数名
{
mstrLog=MFT("[%s]%s<%s 行号:%d>-%s\n",mTime.data(),sType.data(),pFunction,line,content.data());
}
#ifdef _DEBUG
if(mLevel<DEG_OUT_LOG_LEVEL)//日志等级低于 DEG_OUT_LOG_LEVEL 打印在输出窗口
{
MTRACE(mstrLog.data());//TRACE输出长度太短,自己写的输出函数
}
#endif
std::lock_guard<std::mutex> lck(mutex_file);
if (mf.sFlash.length()>MAX_FILE_SIZE)//防止 sFlash 过大,丢掉重新生成
{
mf.sFlash="";
mf.ct_line=0;
mf.t=clock();
}
mf.sFlash.append(mstrLog);
mf.ct_line++;
return ;
}
/****************************
作用:读日志
******************************/
std::vector<std::string> CLog::ReadFile()
{
fstream mFileRead;
if (csReadFilePath.GetLength()==0)
{
csReadFilePath=csFullWriteFilePath;
}
std::vector<std::string> svt(121);
mFileRead.open(csReadFilePath,ios::in);//只读
if(!mFileRead.is_open())
{
string strLog=MFT("打开 %s 失败",CMyTool::Wchar_tToChar_UnicodeToAnsi(csReadFilePath).data());
TRACE("打开 %s 失败\n",strLog.data());
//LOG_E(strLog,"");
return svt;
}
char readLine_char[10240];//日志文件一行很长这个再加大
memset(readLine_char,0,10240);
TRACE("开始读取 %s 请稍后\n",CMyTool::Wchar_tToChar_UnicodeToAnsi(csReadFilePath).data());
int iLineCount=0;
long t=clock();
while (mFileRead.getline(readLine_char,10240))
{
std::string str(readLine_char);
svt.push_back(str);
memset(readLine_char,0,10240);
iLineCount++;
}
reverse(svt.begin(),svt.end());//调整顺序,新的在前面
t=clock()-t;
TRACE("读取%s完毕 一共 %d 行 用时%d ms \n",
CMyTool::Wchar_tToChar_UnicodeToAnsi(csReadFilePath).data(),iLineCount,t);
return svt;
}
###MyLog.h
#pragma once
#include "Log.h"
#define LOG_O(content,stime,username) MyLog::GetInstance()->MakeWriteText(MyLog::GetInstance()->p_log,content,OPT,"-OPT-",__LINE__,__FUNCTION__,stime,username)
#define LOG_E(content,stime) MyLog::GetInstance()->MakeWriteText(MyLog::GetInstance()->p_log,content,ERR,"-ERR-",__LINE__,__FUNCTION__,stime)
#define LOG_W(content,stime) MyLog::GetInstance()->MakeWriteText(MyLog::GetInstance()->p_log,content,WAR,"-WAR-",__LINE__,__FUNCTION__,stime)
#define LOG_I(content,stime) MyLog::GetInstance()->MakeWriteText(MyLog::GetInstance()->p_log,content,INF,"-INF-",__LINE__,__FUNCTION__,stime)
#define INFO_SQL(content) MyLog::GetInstance()->MakeWriteText(MyLog::GetInstance()->p_info,content,SQL,"-SQL-",__LINE__,__FUNCTION__)
#define INFO_TCP(content) MyLog::GetInstance()->MakeWriteText(MyLog::GetInstance()->p_info,content,TCP,"-TCP-",__LINE__,__FUNCTION__)
#define INFO_S(content) MyLog::GetInstance()->MakeWriteText(MyLog::GetInstance()->p_info,content,SYS,"-SYS-",__LINE__,__FUNCTION__)
#define INFO_D(content) MyLog::GetInstance()->MakeWriteText(MyLog::GetInstance()->p_info,content,DBG,"-DBG-",__LINE__,__FUNCTION__)
#define READLOG(p,filename) p->StartReadThread(filename)
class MyLog
{
private:
static MyLog * _instance;
static UINT ThreadWriteDataToFile(LPVOID lp);
static UINT ThreadReadDataFromFile(LPVOID lp);
private:
MyLog();
~MyLog(void);
public:
static MyLog* GetInstance();
CLog *p_log;
CLog *p_info;
void MakeWriteText(CLog *plog,std::string content,UINT mLevel,std::string sType, int line,const char* pFunction,std::string mTime="",std::string userName="");
private:
class CGarbo // 在析构函数中删除MyLog的实例
{
public:
~CGarbo()
{
if(MyLog::_instance)
{
delete MyLog::_instance;
MyLog::_instance = NULL;
}
}
};
static CGarbo garbo;
};
###MyLog.cpp
#include "stdafx.h"
#include "MyTool.h"
#include "MyLog.h"
#define _LOG_ _T(".log") // log日志后缀名
#define _INFO_ _T(".info")//info 程序运行日志后缀名
#define _LOG_DIR_ _T("log\\")//log日志存放文件夹
#define _INFO_DIR_ _T("info\\")//info 程序运行日志存放文件夹
MyLog * MyLog::_instance=MyLog::GetInstance();
MyLog::CGarbo MyLog::garbo;
MyLog* MyLog::GetInstance()
{
if (NULL == _instance)
{
_instance = new MyLog();
}
return _instance;
}
MyLog::MyLog()
{
p_log=new CLog(_T(""),_LOG_DIR_,_LOG_);//我要写两种,所以生成两个
p_info=new CLog(_T(""),_INFO_DIR_,_INFO_);
}
MyLog::~MyLog(void)
{
delete p_log;
delete p_info;
}
/***********************
*作用:格式化日志内容
*参数:
*CLog *plog, 日志类指针
*std::string content 日志主体内容
*UINT mLevel 日志等级
*std::string sType 日志类型
*int line 产生日志的代码行号
*const char* pFunction 产生日志的函数名称
*std::string mTime 产生日志时间 为空则自动获取当前时间节点
*std::string userName 登录人员用户名
* 返回
*****************************/
void MyLog::MakeWriteText(CLog *plog,std::string content,UINT mLevel,std::string sType,
int line,const char* pFunction,
std::string mTime/*=""*/,std::string userName/*=""*/)
{
if (content.length()<1)
{
return ;
}
if (mLevel>SQL)
{
if(mTime=="")
{
mTime=CMyTool::GetTimeString();
}
}else if (mLevel<=mLevel&&mLevel>=0)
{
if(mTime=="")
{
mTime=CMyTool::GetTimeWithMillisecondsString();
}
}
plog->MakeWriteText(content,mLevel,sType,line,pFunction,mTime,userName);
return ;
}
###MyTool.h
#pragma once
#include <string>
#include <map>
#include <vector>
#include <string>
using namespace std;
#define MAX_CHAR_COUNT 1024000 //生成字符串最大长度
#define MFT(format,...) CMyTool::FormatMyStr(format, ##__VA_ARGS__)
#define MTRACE(format,...) CMyTool::OutPutMyDebugStr(format, ##__VA_ARGS__)
#define LOCK_MAP(hMutex) WaitForSingleObject(hMutex,INFINITE)
#define ULOCK_MAP(hMutex) ReleaseMutex(hMutex)
class CMyTool
{
public:
CMyTool(void);
~CMyTool(void);
//计算循环校验码 (子程序)
static CString GetExePath();
static BOOL IsDirExsit(CString mPath,int mStartPos=0);
static CString GetDate();
static CString GetTimeCString(BOOL mIsNeedDate=FALSE);
static string GetTimeString(BOOL mIsNeedDate=FALSE);
static string Get_GMT_Time_String(BOOL mIsNeedDate=FALSE);
static CString GetTimeWithMillisecondsCString(BOOL mIsNeedDate=FALSE);
static string GetTimeWithMillisecondsString(BOOL mIsNeedDate=FALSE);
/********************************************
*作用:UNICEDE 字符集下CString (w_char*)转char*
*参数:char * ansiChar 二进制字符串指针
*返回值:strResult UNICODE string字符串 string转char* sIp.c_str();
********************************************/
static std::string Wchar_tToChar_UnicodeToAnsi(CString unicodeStr);
/********************************************
*作用:UNICODE字符集下char*转string(w_char)
*参数:char * ansiChar 二进制字符串指针
*返回值:strResult UNICODE string字符串
********************************************/
static CString CharToWchar_t_AnsiToUnicode(const char* pCStrKey);
static std::string string_To_UTF8(const std::string & str);
/********************************************
*作用:std::string 拼接,作用相当于CString::Format函数
********************************************/
static std::string FormatMyStr(const char *format,...);
/********************************************
*作用:TRACE有长度限制,这是TRACE加大版 调用用 MTRACE(....);
********************************************/
static int OutPutMyDebugStr(const char *format,...);
/***************************
*作用:字符串分割
*参数:
*std::string strType 数据类型,比如接收,发送
*BYTE *pBuff BYTE 类型数据
*int len pBuff 长度
******************************/
static string ShowHex(string strType,BYTE *pBuff,int len);
/***************************
*作用:字符串分割
*参数:
*std::string str 需要分割的字符串
*std::string pat 分割符号
*bool isRemovePat 是否去掉分隔符
*int patSplitPos 仅isRemovePat为false 有效.取分隔符中的patSplitPos个取全部字符,
如果isRemovePat为false 且未指定patSplitPos,默认取全部,及分割的字符串结尾为pat
比如
string str="{\"KEY\":1,\"KEY_FNC\":\"HAHAHHAHA\"}{\"FNC\":1,\"KEY_FNC\":\"BBBB\"}";
std::vector<std::string> plits = split(str, "}{\"",false,1);
结果为:
{"KEY":1,"KEY_FNC":"HAHAHHAHA"}
{"FNC":1,"KEY_FNC":"BBBB"}
std::vector<std::string> plits = split(str, "}{\"",false);
结果为:
{"KEY":1,"KEY_FNC":"HAHAHHAHA"}{"
FNC":1,"KEY_FNC":"BBBB"}
返回值: 返回分割好的字符串数列
*********************************/
static std::vector<std::string> split(std::string str, std::string pat,bool isRemovePat,int patSplitPos=-1);
/******************************************************
*作用:替换字符串中的某个字符并转换大小写
*参数:
*string oldStr 需要转换的字符串
*string bereplasedStr 被替换的字符串
*string replaseStr 替换的字符串
*int isTrans=0 0 不需要转换大小写 1转小写 2 转大写
返回值: string retStr 返回替换后的字符串
************************************************************/
static string ReplaseMyStringAndTolowerOrUpper(string oldStr,string bereplasedStr,string replaseStr,int isTrans=0);
};
###MyTool.cpp
#include "stdafx.h"
#include <algorithm>
#include "MyTool.h"
CMyTool::CMyTool(void)
{
}
CMyTool::~CMyTool(void)
{
}
CString CMyTool::GetExePath()
{
CString csRunPath;
GetModuleFileName(NULL,csRunPath.GetBuffer(MAX_PATH),MAX_PATH);
csRunPath.ReleaseBuffer();
int pos=csRunPath.ReverseFind('\\');
if (pos != -1 )
{
csRunPath = csRunPath.Left(pos+1);
}
csRunPath.ReleaseBuffer();
return csRunPath;
}
BOOL CMyTool::IsDirExsit(CString mPath,int mStartPos)
{
int pos=mPath.Find(_T("\\"),mStartPos);
while (pos!=-1)
{
CString csDir=mPath.Left(pos+1);
DWORD findDirRet=GetFileAttributes(csDir);
if (findDirRet==0xFFFFFFFF)
{
CreateDirectory(csDir,NULL);
}
pos=mPath.Find(_T("\\"),pos+1);
}
return TRUE;
}
CString CMyTool::GetDate()
{
_SYSTEMTIME st;
GetLocalTime(&st);
CString csDate;
csDate.Format(_T("%d-%02d-%02d"),st.wYear,st.wMonth,st.wDay);
return csDate;
}
CString CMyTool::GetTimeCString(BOOL mIsNeedDate/*=FALSE*/)
{
_SYSTEMTIME st;
GetLocalTime(&st);
CString strTime;
if (mIsNeedDate)
{
strTime.Format(_T("%d年%02d月%02d日%02d:%02d:%02d"),
st.wYear,st.wMonth,st.wDay, st.wHour,st.wMinute,st.wSecond);
}else
{
strTime.Format(_T("%02d:%02d:%02d"),
st.wHour,st.wMinute,st.wSecond);
}
return strTime;
}
string CMyTool::GetTimeString(BOOL mIsNeedDate/*=FALSE*/)
{
_SYSTEMTIME st;
GetLocalTime(&st);
string strTime="";
if (mIsNeedDate)
{
strTime=FormatMyStr("%d年%02d月%02d日%02d:%02d:%02d",
st.wYear,st.wMonth,st.wDay, st.wHour,st.wMinute,st.wSecond);
}else
{
strTime=FormatMyStr("%02d:%02d:%02d",
st.wHour,st.wMinute,st.wSecond);
}
return strTime;
}
string CMyTool::Get_GMT_Time_String(BOOL mIsNeedDate/*=FALSE*/)
{
time_t t = time( NULL );
tm gmtm;
gmtime_s(&gmtm,&t);
char tmpbuf[128]={0};;
// //Tue, 23 Aug 2022 05:15:44 GMT
setlocale(LC_TIME, "en_US.UTF-8");//没有这句有中文
strftime(tmpbuf, 128, "%a, %d %b %Y %H:%M:%S GMT", &gmtm);
string strTime=FormatMyStr("%s",tmpbuf);
return strTime;
}
CString CMyTool::GetTimeWithMillisecondsCString(BOOL mIsNeedDate/*=FALSE*/)
{
_SYSTEMTIME st;
GetLocalTime(&st);
CString strTime;
if (mIsNeedDate)
{
strTime.Format(_T("%d年%02d月%02d日%02d:%02d:%02d:%03d"),
st.wYear,st.wMonth,st.wDay, st.wHour,st.wMinute,st.wSecond);
}else
{
strTime.Format(_T("%02d:%02d:%02d:%03d"),
st.wHour,st.wMinute,st.wSecond,st.wMilliseconds);
}
return strTime;
}
string CMyTool::GetTimeWithMillisecondsString(BOOL mIsNeedDate/*=FALSE*/)
{
_SYSTEMTIME st;
GetLocalTime(&st);
string strTime="";
if (mIsNeedDate)
{
strTime=FormatMyStr("%d年%02d月%02d日%02d:%02d:%02d:%03d",
st.wYear,st.wMonth,st.wDay, st.wHour,st.wMinute,st.wSecond,st.wMilliseconds);
}else
{
strTime=FormatMyStr("%02d:%02d:%02d:%03d",
st.wHour,st.wMinute,st.wSecond,st.wMilliseconds);
}
return strTime;
}
/********************************************
*作用:UNICEDE 字符集下CString (w_char*)转char*
*参数:char * ansiChar 二进制字符串指针
*返回值:strResult UNICODE string字符串 string转char* sIp.c_str();
********************************************/
std::string CMyTool::Wchar_tToChar_UnicodeToAnsi(CString unicodeStr)
{
#ifdef _UNICODE
wchar_t * mWchar=unicodeStr.GetBuffer(unicodeStr.GetLength());
//第一次调用确认转换后单字节字符串的长度,用于开辟空间
int pSize = WideCharToMultiByte(CP_OEMCP, 0, mWchar, wcslen(mWchar), NULL, 0, NULL, NULL);
if(pSize==0)
{
unicodeStr.ReleaseBuffer();
return "";
}
char* pCStrKey = new char[pSize+1];
//第二次调用将双字节字符串转换成单字节字符串
WideCharToMultiByte(CP_OEMCP, 0, mWchar, wcslen(mWchar), pCStrKey, pSize, NULL, NULL);
pCStrKey[pSize] = '\0';
// return pCStrKey;
//如果想要转换成std::string,直接赋值即可
string str = pCStrKey;
unicodeStr.ReleaseBuffer();
delete []pCStrKey;
#else
string str=unicodeStr.GetBuffer(unicodeStr.GetLength());
unicodeStr.ReleaseBuffer();
#endif
return str;
}
/********************************************
*作用:UNICODE字符集下char*转string(w_char)
*参数:char * ansiChar 二进制字符串指针
*返回值:strResult UNICODE string字符串
********************************************/
CString CMyTool::CharToWchar_t_AnsiToUnicode(const char* pCStrKey)
{
// char* pCStrKey = pKey.data();
//第一次调用返回转换后的字符串长度,用于确认为wchar_t*开辟多大的内存空间
int pSize = MultiByteToWideChar(CP_OEMCP, 0, pCStrKey, strlen(pCStrKey) + 1, NULL, 0);
TCHAR *pWCStrKey = new TCHAR[pSize+1];
//第二次调用将单字节字符串转换成双字节字符串
MultiByteToWideChar(CP_OEMCP, 0, pCStrKey, strlen(pCStrKey) + 1, pWCStrKey, pSize);
pWCStrKey[pSize] = '\0';
CString wstr(pWCStrKey);
delete []pWCStrKey;
pWCStrKey=NULL;
return wstr;
}
std::string CMyTool::string_To_UTF8(const std::string & str)
{
int nwLen = ::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, NULL, 0);
wchar_t * pwBuf = new wchar_t[nwLen + 1];//一定要加1,不然会出现尾巴
ZeroMemory(pwBuf, nwLen * 2 + 2);
::MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.length(), pwBuf, nwLen);
int nLen = ::WideCharToMultiByte(CP_UTF8, 0, pwBuf, -1, NULL, NULL, NULL, NULL);
char * pBuf = new char[nLen + 1];
ZeroMemory(pBuf, nLen + 1);
::WideCharToMultiByte(CP_UTF8, 0, pwBuf, nwLen, pBuf, nLen, NULL, NULL);
std::string retStr(pBuf);
delete []pwBuf;
delete []pBuf;
pwBuf = NULL;
pBuf = NULL;
return retStr;
}
std::string CMyTool::FormatMyStr(const char *format,...)
{
va_list argptr;
va_start(argptr, format);
char* buf = (char*)malloc(MAX_CHAR_COUNT);
_vsnprintf_s(buf,MAX_CHAR_COUNT,MAX_CHAR_COUNT,format,argptr);
va_end(argptr);
std::string str(buf);
free(buf);
return str;
}
int CMyTool::OutPutMyDebugStr(const char *format,...)
{
va_list argptr;
va_start(argptr, format);
char* buf = (char*)malloc(MAX_CHAR_COUNT);
_vsnprintf_s(buf,MAX_CHAR_COUNT,MAX_CHAR_COUNT,format,argptr);
va_end(argptr);
std::string str(buf);
free(buf);
OutputDebugStringA(str.data());
return str.length();
}
string CMyTool::ShowHex(string strType,BYTE * pBuff,int len)
{
string str;
string strRet=MFT("%s %d\n",strType.data(),len);
for (int i = 0; i < len; i++)
{
str="";
str=MFT("%02X ",pBuff[i]);
strRet.append(str);
}
// strRet.append("\n");
//MTRACE(strRet.data());
return strRet;
}
/***************************
*作用:字符串分割
*参数:
*std::string str 需要分割的字符串
*std::string pat 分割符号
*bool isRemovePat 是否去掉分隔符
*int patSplitPos 仅isRemovePat为false 有效.取分隔符中的patSplitPos个取全部字符,
如果isRemovePat为false 且未指定patSplitPos,默认取全部,及分割的字符串结尾为pat
比如
string str="{\"KEY\":1,\"KEY_FNC\":\"HAHAHHAHA\"}{\"FNC\":1,\"KEY_FNC\":\"BBBB\"}";
std::vector<std::string> plits = split(str, "}{\"",false,1);
结果为:
{"KEY":1,"KEY_FNC":"HAHAHHAHA"}
{"FNC":1,"KEY_FNC":"BBBB"}
std::vector<std::string> plits = split(str, "}{\"",false);
结果为:
{"KEY":1,"KEY_FNC":"HAHAHHAHA"}{"
FNC":1,"KEY_FNC":"BBBB"}
返回值: 返回分割好的字符串数列
*********************************/
std::vector<std::string> CMyTool::split(std::string str, std::string pat,bool isRemovePat,int patSplitPos/*=-1*/)
{
if(patSplitPos==-1)
{
patSplitPos=pat.size();
}
std::vector<std::string> bufStr;
while (true)
{
int index = str.find(pat);
int iSplitPos=0;//分割点
int iEraserPos=0;//分割点
if (isRemovePat||index==-1)//如果去掉分割字符串
{
iSplitPos=index;
iEraserPos=index+ pat.size();
}else
{
iSplitPos =index+patSplitPos;
iEraserPos=index+ patSplitPos;
}
std::string subStr = str.substr(0, iSplitPos);
if (!subStr.empty())
{
bufStr.push_back(subStr);
}
str.erase(0, iEraserPos);
if (index == -1)
break;
}
return bufStr;
}
/******************************************************
*作用:替换字符串中的某个字符
*参数:
*string oldStr 需要转换的字符串
*string bereplasedStr 被替换的字符串
*string replaseStr 替换的字符串
*int isTrans=0 0 不需要转换大小写 1转小写 2 转大写
返回值: string retStr 返回替换后的字符串
************************************************************/
string CMyTool::ReplaseMyStringAndTolowerOrUpper(string oldStr,string bereplasedStr,string replaseStr,int isTrans)
{
string retStr=oldStr;
switch (isTrans)
{
case 1:
transform(retStr.begin(),retStr.end(),retStr.begin(),::tolower);
break;
case 2:
transform(retStr.begin(),retStr.end(),retStr.begin(),::toupper);
break;
default:
break;
}
int bLen=bereplasedStr.length();
if(bLen==0)
{
return retStr;
}
int repLen=replaseStr.length();
int pos =0;
pos = retStr.find(bereplasedStr,pos);
while(pos != -1)
{
retStr.replace(pos,bLen,replaseStr);
pos = retStr.find(bereplasedStr,pos+repLen);
}
return retStr;
}
###测试
UINT ThreadWriteLog3(LPVOID lp)
{
int id = GetCurrentThreadId();
CThreadWriteLogTestDlg *p=(CThreadWriteLogTestDlg*)lp;
//debug
DWORD ts=GetTickCount();
int mk=0;
while (p->bIsWrite)
{
mk++;
string slog=MFT("%08d__%050d",id,mk);
LOG_W(slog,"");
INFO_S(slog);
}
DWORD te=GetTickCount();
int dt=(int)(te-ts);
float fb=(float)dt/mk;
TRACE("线程 %d 生成并写入 %d 行 用时=%d ms , 平均一行用时 %lf ms \n" ,id,mk,dt,fb);
return 0;
}
void CThreadWriteLogTestDlg::OnBnClickedButtonStart()
{
bIsWrite=TRUE;
//MyLog测试
pThread=AfxBeginThread(ThreadWriteLog3,this,THREAD_PRIORITY_BELOW_NORMAL);
pThread2=AfxBeginThread(ThreadWriteLog3,this,THREAD_PRIORITY_BELOW_NORMAL);
//MyEasyLog测试
//pThread3=AfxBeginThread(ThreadWriteLog,this,THREAD_PRIORITY_BELOW_NORMAL);
//pThread4=AfxBeginThread(ThreadWriteLog,this,THREAD_PRIORITY_BELOW_NORMAL);
GetDlgItem(IDC_BUTTON_START)->EnableWindow(FALSE);
}
void CThreadWriteLogTestDlg::OnBnClickedButtonStop()
{
bIsWrite=FALSE;
if(pThread)
{
WaitForSingleObject(pThread->m_hThread,INFINITE);
pThread=NULL;
}
if(pThread2)
{
WaitForSingleObject(pThread2->m_hThread,INFINITE);
pThread2=NULL;
}
//if(pThread3)
//{
// WaitForSingleObject(pThread3->m_hThread,INFINITE);
// pThread3=NULL;
//}
//if(pThread4)
//{
// WaitForSingleObject(pThread3->m_hThread,INFINITE);
// pThread4=NULL;
//}
GetDlgItem(IDC_BUTTON_START)->EnableWindow(TRUE);
}
void CThreadWriteLogTestDlg::OnBnClickedButtonRead()
{
// TODO: 在此添加控件通知处理程序代码
READLOG(MyLog::GetInstance()->p_log,_T(""));
}