开始我的第一个vc模块的设计。
这个是一个vc的写日志的类,为什么叫CLog3...因为之前有两版写log的类,但是都是用C#写的,所以这个vc写的就叫CLog3吧。
功能只是简单模拟C#中的写Log的方法的设计。
设计思路:
因为在程序运行过程中, 需要记录一些信息到log中, 同时要尽量减少对主处理模块的影响,减少i|o的操作,所以CLog3中设计的思路为自己创建一个Thread,该Thread会获取一个队列中的讯息,当要写一个讯息的时候, 将要写的信息添加到队列中,并通知Thread获取队列中的资料,写入已经打开的文件中。
因为在StartLog的时候,就已经将一个CFile对象打开了,所以减少了写是在Open的操作。
而调用方只是将要写的log扔到队列中,然后就可以继续处理自己的事情了,不用等待log写完后在处理,减少了对主模块的影响。
该开发环境是windows 2003 + vc.net 2005, 因为vc.net 2005中默认开启了Unicode 的模式,所以要写汉字到文件需要将CString转换成char * ,祥见: http://www.cnblogs.com/zhucl1006/archive/2008/01/02/1023380.html
Clog3.h
/* 一个写log的类
时间 :2008-1-2
版本 :1.0.0.0
作者 :Karl.zhu
*/
#pragma once
#include <afxmt.h>
// CLog3 命令目标
class CLog3
{
public:
CLog3();
void Init(CString FilePath,CString FileName);
virtual ~CLog3();
public :
CString m_FilePath;
CString m_FileName;
DWORD m_Fileday;
CFile m_File;
HANDLE m_processStopHandle,m_processSignalHandle,m_processThreadHandle;
CStringList m_messageQueue;
CMutex m_mutex;
static void LogProcessorThread(LPVOID data);
void QueueMessage(CString szLogEntry);
void StartLog();
void StopLog();
void CrateLog(CString csFilePath,CString csFileName);
};
时间 :2008-1-2
版本 :1.0.0.0
作者 :Karl.zhu
*/
#pragma once
#include <afxmt.h>
// CLog3 命令目标
class CLog3
{
public:
CLog3();
void Init(CString FilePath,CString FileName);
virtual ~CLog3();
public :
CString m_FilePath;
CString m_FileName;
DWORD m_Fileday;
CFile m_File;
HANDLE m_processStopHandle,m_processSignalHandle,m_processThreadHandle;
CStringList m_messageQueue;
CMutex m_mutex;
static void LogProcessorThread(LPVOID data);
void QueueMessage(CString szLogEntry);
void StartLog();
void StopLog();
void CrateLog(CString csFilePath,CString csFileName);
};
CLog3.cpp
//
//
/* 一个写log的类
时间 :2008-1-2
版本 :1.0.0.0
作者 :Karl.zhu
*/
#include "stdafx.h"
#include "Log3Demo.h"
#include "Log3.h"
#include <process.h>
// CLog3
CLog3::CLog3()
{
}
void CLog3::Init(CString FilePath,CString FileName)
{
m_FilePath = FilePath;
m_FileName = FileName;
}
CLog3::~CLog3()
{
}
// CLog3 成员函数
void CLog3::CrateLog(CString csFilePath,CString csFileName)
{
try
{
this->m_mutex.Lock();
CFileFind find ;
if (!find.FindFile(csFilePath))
{
CreateDirectory(csFilePath,NULL);
}
CString filename,fileexe;
int Where = csFileName.ReverseFind(_T('.'));
if (Where != -1)
{
filename = csFileName.Left(Where);
fileexe = csFileName.Right(csFileName.GetLength() - Where - 1);
}
else
{
filename = csFileName;
fileexe = "";
}
CTime now_time ;
SYSTEMTIME tm;
GetLocalTime(&tm);
CString day;
day.Format(_T("_%02d"),tm.wDay);
CString FileFullPath;
FileFullPath.Format(_T("%s\\%s%s.%s"),csFilePath,filename,day,fileexe);
if (m_File.m_hFile != CFile::hFileNull)
{
m_File.Close();
}
if (!find.FindFile(FileFullPath,NULL))
{
//没有找到
if (!m_File.Open(FileFullPath,CFile::modeCreate|CFile::modeReadWrite| CFile::shareDenyNone))
{
AfxMessageBox(_T("Open File Error"));
}
this->m_Fileday = tm.wDay;
}
else
{
//找到
WIN32_FIND_DATA FindFileData;
FindClose(FindFirstFile(FileFullPath,&FindFileData));
SYSTEMTIME csCreateTime;
FileTimeToSystemTime(&FindFileData.ftCreationTime,&csCreateTime);
if (tm.wDay == csCreateTime.wDay && tm.wMonth == csCreateTime.wMonth && tm.wYear == csCreateTime.wYear)
{
if(!m_File.Open(FileFullPath,CFile::modeReadWrite| CFile::shareDenyNone))
{
AfxMessageBox(_T("Open Log Error"));
}
this->m_Fileday = tm.wDay;
}
else
{
if (!m_File.Open(FileFullPath,CFile::modeCreate | CFile::modeReadWrite | CFile::shareDenyNone))
{
AfxMessageBox(_T("Open Log Error"));
}
else{
FILETIME ft;
SystemTimeToFileTime(&tm,&ft);
SetFileTime(m_File.m_hFile,&ft,&ft,&ft);
this->m_Fileday = tm.wDay;
}
}
//memset(&FileInfo,0,sizeof(FILE_INFO));
}
}
catch ()
{
DWORD lastError = GetLastError();
CString Err ;
Err.Format(_T("%d"),lastError);
AfxMessageBox(Err);
}
this->m_mutex.Unlock();
}
void CLog3::StartLog()
{
CrateLog(m_FilePath,m_FileName);
this->m_processStopHandle = CreateEvent(NULL,TRUE,FALSE,NULL);
this->m_processSignalHandle = CreateEvent(NULL,TRUE,FALSE,NULL);
m_processThreadHandle = HANDLE(_beginthread(LogProcessorThread, 0, this));
if(m_processThreadHandle != LPVOID(-1))
{
AfxMessageBox(_T("Log Thread OK"));
}
else
{
AfxMessageBox(_T("Log Thread Faild"));
}
}
void CLog3::StopLog()
{
SetEvent(this->m_processStopHandle);
}
void CLog3::LogProcessorThread(LPVOID data)
{
CLog3 *me = (CLog3 *) data;
BOOL bStop = FALSE;
DWORD dwWritten;
HANDLE hHandleArray[2];
ASSERT(me);
hHandleArray[0] = me->m_processStopHandle;
hHandleArray[1] = me->m_processSignalHandle;
CString csData;
while (bStop == FALSE)
{
switch (WaitForMultipleObjects(2, hHandleArray, FALSE, INFINITE))
{
case WAIT_OBJECT_0:
bStop = TRUE;
break;
case WAIT_OBJECT_0 + 1:
// Lock the queue to get the count and the next entry
SYSTEMTIME tm1;
GetLocalTime(&tm1);
if (me->m_Fileday != tm1.wDay)
{
me->CrateLog(me->m_FilePath,me->m_FileName);
}
me->m_mutex.Lock();
while (me->m_messageQueue.GetCount())
{
csData = me->m_messageQueue.RemoveTail();
SYSTEMTIME tm;
GetLocalTime(&tm);
CString csFullData;
csFullData.Format(_T("%02d:%02d:%02d[%03d] %s"),tm.wHour,tm.wMinute,tm.wSecond,tm.wMilliseconds,csData);
// Now unlock the queue while we write
me->m_mutex.Unlock();
// Seek to the end of the file
me->m_File.SeekToEnd();
DWORD leg = WideCharToMultiByte(CP_OEMCP,NULL,csFullData,-1,NULL,0,NULL,FALSE);
CHAR strchar [5000];
WideCharToMultiByte(CP_OEMCP,NULL,csFullData,-1,strchar,leg,NULL,FALSE);
me->m_File.Write(strchar,strlen(strchar));
CHAR * endline ="\r\n";
me->m_File.Write(endline,strlen(endline));
me->m_mutex.Lock();
}
// Now unlock it again
me->m_mutex.Unlock();
// Force output to disk
me->m_File.Flush();
ResetEvent(me->m_processSignalHandle);
break;
}
}
me->m_File.Close();
AfxMessageBox(_T("end File"));
_endthread();
}
void CLog3::QueueMessage(CString szLogEntry)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
ASSERT(szLogEntry);
ASSERT(AfxIsValidString(szLogEntry));
// Lock the object for the addhead call
// (must be fast once we get the lock).
m_mutex.Lock();
m_messageQueue.AddHead(szLogEntry);
m_mutex.Unlock();
// Now tell our processing thread there's
// new stuff to write
SetEvent(m_processSignalHandle);
}
//
/* 一个写log的类
时间 :2008-1-2
版本 :1.0.0.0
作者 :Karl.zhu
*/
#include "stdafx.h"
#include "Log3Demo.h"
#include "Log3.h"
#include <process.h>
// CLog3
CLog3::CLog3()
{
}
void CLog3::Init(CString FilePath,CString FileName)
{
m_FilePath = FilePath;
m_FileName = FileName;
}
CLog3::~CLog3()
{
}
// CLog3 成员函数
void CLog3::CrateLog(CString csFilePath,CString csFileName)
{
try
{
this->m_mutex.Lock();
CFileFind find ;
if (!find.FindFile(csFilePath))
{
CreateDirectory(csFilePath,NULL);
}
CString filename,fileexe;
int Where = csFileName.ReverseFind(_T('.'));
if (Where != -1)
{
filename = csFileName.Left(Where);
fileexe = csFileName.Right(csFileName.GetLength() - Where - 1);
}
else
{
filename = csFileName;
fileexe = "";
}
CTime now_time ;
SYSTEMTIME tm;
GetLocalTime(&tm);
CString day;
day.Format(_T("_%02d"),tm.wDay);
CString FileFullPath;
FileFullPath.Format(_T("%s\\%s%s.%s"),csFilePath,filename,day,fileexe);
if (m_File.m_hFile != CFile::hFileNull)
{
m_File.Close();
}
if (!find.FindFile(FileFullPath,NULL))
{
//没有找到
if (!m_File.Open(FileFullPath,CFile::modeCreate|CFile::modeReadWrite| CFile::shareDenyNone))
{
AfxMessageBox(_T("Open File Error"));
}
this->m_Fileday = tm.wDay;
}
else
{
//找到
WIN32_FIND_DATA FindFileData;
FindClose(FindFirstFile(FileFullPath,&FindFileData));
SYSTEMTIME csCreateTime;
FileTimeToSystemTime(&FindFileData.ftCreationTime,&csCreateTime);
if (tm.wDay == csCreateTime.wDay && tm.wMonth == csCreateTime.wMonth && tm.wYear == csCreateTime.wYear)
{
if(!m_File.Open(FileFullPath,CFile::modeReadWrite| CFile::shareDenyNone))
{
AfxMessageBox(_T("Open Log Error"));
}
this->m_Fileday = tm.wDay;
}
else
{
if (!m_File.Open(FileFullPath,CFile::modeCreate | CFile::modeReadWrite | CFile::shareDenyNone))
{
AfxMessageBox(_T("Open Log Error"));
}
else{
FILETIME ft;
SystemTimeToFileTime(&tm,&ft);
SetFileTime(m_File.m_hFile,&ft,&ft,&ft);
this->m_Fileday = tm.wDay;
}
}
//memset(&FileInfo,0,sizeof(FILE_INFO));
}
}
catch ()
{
DWORD lastError = GetLastError();
CString Err ;
Err.Format(_T("%d"),lastError);
AfxMessageBox(Err);
}
this->m_mutex.Unlock();
}
void CLog3::StartLog()
{
CrateLog(m_FilePath,m_FileName);
this->m_processStopHandle = CreateEvent(NULL,TRUE,FALSE,NULL);
this->m_processSignalHandle = CreateEvent(NULL,TRUE,FALSE,NULL);
m_processThreadHandle = HANDLE(_beginthread(LogProcessorThread, 0, this));
if(m_processThreadHandle != LPVOID(-1))
{
AfxMessageBox(_T("Log Thread OK"));
}
else
{
AfxMessageBox(_T("Log Thread Faild"));
}
}
void CLog3::StopLog()
{
SetEvent(this->m_processStopHandle);
}
void CLog3::LogProcessorThread(LPVOID data)
{
CLog3 *me = (CLog3 *) data;
BOOL bStop = FALSE;
DWORD dwWritten;
HANDLE hHandleArray[2];
ASSERT(me);
hHandleArray[0] = me->m_processStopHandle;
hHandleArray[1] = me->m_processSignalHandle;
CString csData;
while (bStop == FALSE)
{
switch (WaitForMultipleObjects(2, hHandleArray, FALSE, INFINITE))
{
case WAIT_OBJECT_0:
bStop = TRUE;
break;
case WAIT_OBJECT_0 + 1:
// Lock the queue to get the count and the next entry
SYSTEMTIME tm1;
GetLocalTime(&tm1);
if (me->m_Fileday != tm1.wDay)
{
me->CrateLog(me->m_FilePath,me->m_FileName);
}
me->m_mutex.Lock();
while (me->m_messageQueue.GetCount())
{
csData = me->m_messageQueue.RemoveTail();
SYSTEMTIME tm;
GetLocalTime(&tm);
CString csFullData;
csFullData.Format(_T("%02d:%02d:%02d[%03d] %s"),tm.wHour,tm.wMinute,tm.wSecond,tm.wMilliseconds,csData);
// Now unlock the queue while we write
me->m_mutex.Unlock();
// Seek to the end of the file
me->m_File.SeekToEnd();
DWORD leg = WideCharToMultiByte(CP_OEMCP,NULL,csFullData,-1,NULL,0,NULL,FALSE);
CHAR strchar [5000];
WideCharToMultiByte(CP_OEMCP,NULL,csFullData,-1,strchar,leg,NULL,FALSE);
me->m_File.Write(strchar,strlen(strchar));
CHAR * endline ="\r\n";
me->m_File.Write(endline,strlen(endline));
me->m_mutex.Lock();
}
// Now unlock it again
me->m_mutex.Unlock();
// Force output to disk
me->m_File.Flush();
ResetEvent(me->m_processSignalHandle);
break;
}
}
me->m_File.Close();
AfxMessageBox(_T("end File"));
_endthread();
}
void CLog3::QueueMessage(CString szLogEntry)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
ASSERT(szLogEntry);
ASSERT(AfxIsValidString(szLogEntry));
// Lock the object for the addhead call
// (must be fast once we get the lock).
m_mutex.Lock();
m_messageQueue.AddHead(szLogEntry);
m_mutex.Unlock();
// Now tell our processing thread there's
// new stuff to write
SetEvent(m_processSignalHandle);
}
这个算是我第一个vc的code,可能也存在什么不妥之处,读者们见笑了。