记录 C++ 线程安全日志类

11 篇文章 1 订阅
9 篇文章 0 订阅

在这里插入图片描述

线程安全的,应该还有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(""));
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值