这是【带缓存的log写出类】的改进版本;效率比CStdioFile快一倍左右;使用系统API写出文件;使用自带缓存不使用系统文件buffer。
支持文件最大长度是64位长,即两个DWORD长byte数据。
非精确测试,测试结果,单位毫秒,前面是CBufferLog,后面是CStdiofile:
debug版下大致:
714M数据耗时分别是20289和47000;
476M数据耗时分别是13344和26735,
238M数据耗时分别是4961和11633;
感谢cnzdgs 在为期一周的探索过程中的不厌烦的帮助!
优快云帖子地址:http://topic.youkuaiyun.com/u/20080827/09/ea598ffd-340e-41ac-ad84-fd87cf21cce8.html?279638131
因为活又来了,以后有时间再慢慢完善。
TODOList:
1. 使用VirtualAlloc分配页面文件整数倍大小的buffer;
2. 文件相关其他操作函数的支持
3. 使用磁盘映射文件写log还未尝试
所有源码如下(沙漠孤狐 版权所有, Boythl#163.com):
- // BufferLog.h: interface for the CBufferLog class.
- //目标:
- // 1.带缓冲区的文件输出类
- // 2.可自定义缓冲区大小
- // 3.可重定义缓冲区大小
- // 4.缓冲区满时自动写到文件里
- //////////////////////////////////////////////////////////////////////
- #if !defined(AFX_BUFFERLOG_H__0F83C182_4C70_44B0_9F53_D66F43E55FD8__INCLUDED_)
- #define AFX_BUFFERLOG_H__0F83C182_4C70_44B0_9F53_D66F43E55FD8__INCLUDED_
- #if _MSC_VER > 1000
- #pragma once
- #endif // _MSC_VER > 1000
- #include <io.h>
- const DWORD SECTOR_SIZE = 512;//the sector size is 512 bytes
- const UCHAR CHAR_LN[] = {'/r', '/n'}; //换行符
- class CBufferLog
- {
- public:
- CBufferLog(DWORD dwBufferSize = 10000);//单位扇区,默认缓存10000个扇区
- virtual ~CBufferLog();
- virtual void WriteLog( const void* lpBuf, DWORD dwCount );//写log到缓存
- inline virtual void WriteLogLn( const void* lpBuf, DWORD dwCount )//写一行(自动加换行符)到缓存
- { WriteLog(lpBuf, dwCount); WriteLog(CHAR_LN, 2); }
- inline virtual void WriteLogLn( )//写入一空行
- { WriteLog(CHAR_LN, 2); }
- inline void WriteString(const CString& sz){this->WriteLog((LPCTSTR)sz, sz.GetLength());}
- BOOL Open( LPCTSTR lpszFileName, bool Apped = false );//打开log文件,Append是否覆盖已有内容
- void Close( ); //关闭log文件
- DWORD GetPosition();//32位的获取文件指针位置
- DWORD GetPosition(DWORD& High32);//64位的获取文件指针位置
- inline LPCTSTR GetFilePath() const { return this->m_Path; }
- inline DWORD SeekToEnd(){return SetFilePointer(this->m_Handle, 0L, NULL, FILE_END ); }
- inline DWORD SeekToBegin(){return SetFilePointer(this->m_Handle, 0L, NULL, FILE_BEGIN ); }
- protected:
- inline virtual void Flush()//输出缓冲区内容
- {
- this->Write(this->m_dwCurPos);
- this->m_dwCurPos = 0;
- this->m_dwFreeLen = this->m_BufferSize;
- }
- virtual BOOL Write(DWORD dwLen); //写缓冲区内容到磁盘
- DWORD m_BufferSize; //缓存尺寸
- char* m_Buffer; //缓存
- DWORD m_dwCurPos; //当前缓冲区指针位置
- DWORD m_dwFreeLen; //可用缓冲数
- HANDLE m_Handle; //file handle
- CHAR m_Path[MAX_PATH]; //file path
- private:
- DWORD m_dwByteWrittern;
- LPOVERLAPPED m_pOverLapped;
- DWORD m_dwOffsetLow; //文件指针偏移量低位
- DWORD m_dwOffsetHigh; //文件指针偏移量高位
- };
- #endif // !defined(AFX_BUFFERLOG_H__0F83C182_4C70_44B0_9F53_D66F43E55FD8__INCLUDED_)
- // BufferLog.cpp: implementation of the CBufferLog class.
- //
- //////////////////////////////////////////////////////////////////////
- #include "stdafx.h"
- #include "BufferLog.h"
- #include <fcntl.h>
- #include <sys/stat.h>
- #ifdef _DEBUG
- #undef THIS_FILE
- static char THIS_FILE[]=__FILE__;
- #define new DEBUG_NEW
- #endif
- //////////////////////////////////////////////////////////////////////
- // Construction/Destruction
- //////////////////////////////////////////////////////////////////////
- CBufferLog::CBufferLog(DWORD dwBufferSize/* = 10000*/)
- {
- ASSERT(dwBufferSize != 0);
- this->m_dwFreeLen = this->m_BufferSize = dwBufferSize * SECTOR_SIZE;
- this->m_dwByteWrittern = this->m_dwCurPos = 0;
- this->m_Buffer = new char[m_BufferSize];
- memset(this->m_Buffer, 0, m_BufferSize);
- memset(m_Path, 0, MAX_PATH);
- this->m_Handle = NULL;
- this->m_pOverLapped = new OVERLAPPED;
- m_pOverLapped->hEvent = NULL;
- m_pOverLapped->Internal = m_pOverLapped->InternalHigh =
- m_pOverLapped->Offset = m_pOverLapped->OffsetHigh = 0;
- m_pOverLapped->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- this->m_dwOffsetHigh = this->m_dwOffsetLow = 0;
- }
- BOOL CBufferLog::Open( LPCTSTR lpszFileName,
- bool Apped /*= false*/ )
- {
- if (this->m_Handle)
- {
- _ASSERTE(("The file isn't closed, can't open two times!/n", NULL));
- return FALSE;
- }
- this->m_dwFreeLen = this->m_BufferSize;
- this->m_dwByteWrittern = this->m_dwCurPos = 0;
- memset(this->m_Buffer, 0, m_BufferSize);
- memset(m_Path, 0, MAX_PATH);
- m_pOverLapped->hEvent = NULL;
- m_pOverLapped->Internal = m_pOverLapped->InternalHigh =
- m_pOverLapped->Offset = m_pOverLapped->OffsetHigh = 0;
- this->m_dwOffsetLow = this->m_dwOffsetHigh = 0;
- int nCreateFlag = Apped
- ? OPEN_ALWAYS //Opens the file, if it exists.
- //If the file does not exist, the function creates the file
- : CREATE_ALWAYS;//Creates a new file.
- //If the file exists, the function overwrites the file and clears the existing attributes.
- int nFlag = FILE_ATTRIBUTE_NORMAL |
- FILE_FLAG_OVERLAPPED/*异步IO*//* | FILE_FLAG_WRITE_THROUGH*/ | FILE_FLAG_NO_BUFFERING;
- if (INVALID_HANDLE_VALUE ==
- (this->m_Handle = CreateFile(lpszFileName, GENERIC_WRITE | GENERIC_READ,
- FILE_SHARE_READ, NULL, nCreateFlag, nFlag, NULL))
- )//文件打开失败
- {
- this->m_Handle = NULL;
- return FALSE;
- }
- else
- {
- if (Apped) //追写
- {
- this->SeekToEnd();
- this->m_dwOffsetLow = this->GetPosition(this->m_dwOffsetHigh);
- }
- strncpy(this->m_Path, lpszFileName, MAX_PATH - 1);//store the file path
- return TRUE;
- }
- }
- void CBufferLog::Close( )
- {
- if (this->m_Buffer && this->m_dwCurPos != 0)
- {
- LONG lCount = this->m_dwFreeLen;//冗余数据量
- memset(this->m_Buffer + this->m_dwCurPos, 0, this->m_dwFreeLen);//剩余空间用0替补
- this->Write(this->m_BufferSize);//输出整个buffer内容,后面的冗余数据需要删除
- this->m_dwCurPos = 0;//指针复位
- this->m_dwFreeLen = this->m_BufferSize;
- //获取实际文件位置,因为FILE_FLAG_NO_BUFFERING只能整扇区读写
- if (this->m_BufferSize != this->m_dwCurPos)//后面有冗余数据
- {
- while (!HasOverlappedIoCompleted(m_pOverLapped))
- {
- Sleep(0);
- }
- //删除冗余数据
- SetFilePointer(this->m_Handle, -lCount, NULL, FILE_END);//前移到冗余数据前
- SetEndOfFile(this->m_Handle);
- }
- }
- if (this->m_Handle)
- {
- while (!HasOverlappedIoCompleted(m_pOverLapped))
- {
- Sleep(0);
- }
- CloseHandle(this->m_Handle);
- this->m_Handle = NULL;
- }
- }
- CBufferLog::~CBufferLog()
- {
- //关闭文件
- this->Close();
- if (this->m_Buffer)
- {
- delete []m_Buffer;
- this->m_Buffer = NULL;
- }
- if (this->m_pOverLapped)
- {
- delete this->m_pOverLapped;
- this->m_pOverLapped = NULL;
- }
- }
- void CBufferLog::WriteLog(const void *lpBuf, DWORD dwCount)
- {
- if (m_dwFreeLen >= dwCount)
- {
- memcpy(this->m_Buffer + this->m_dwCurPos, lpBuf, dwCount);
- this->m_dwCurPos += dwCount;
- this->m_dwFreeLen -= dwCount;
- }
- else//比缓冲区剩余空间大
- {
- DWORD dwLeft = dwCount; //剩余数量
- while (dwLeft > 0)
- {
- if (m_dwFreeLen >= dwLeft)//缓冲区够用
- {
- memcpy(this->m_Buffer + this->m_dwCurPos,
- (BYTE*)lpBuf + dwCount - dwLeft, dwLeft);
- this->m_dwCurPos += dwLeft;
- this->m_dwFreeLen -= dwLeft;
- dwLeft = 0;
- break;
- }
- else//缓冲区不够
- {
- memcpy(this->m_Buffer + this->m_dwCurPos,
- (BYTE*)lpBuf + dwCount - dwLeft, m_dwFreeLen);
- this->m_dwCurPos += m_dwFreeLen;
- dwLeft -= m_dwFreeLen; //未处理数量
- this->Flush();//缓冲区已满,输出
- }
- }
- }
- }
- DWORD CBufferLog::GetPosition()
- {
- this->Flush();
- return SetFilePointer(this->m_Handle, 0L, NULL, FILE_CURRENT );
- }
- BOOL CBufferLog::Write(DWORD dwLen) //写缓冲区内容到磁盘
- {
- while (!HasOverlappedIoCompleted(m_pOverLapped))
- {
- Sleep(0);
- }
- m_pOverLapped->Offset = this->m_dwOffsetLow;
- m_pOverLapped->OffsetHigh = this->m_dwOffsetHigh;
- if (this->m_dwOffsetLow + dwLen <= 0xFFFFFFFF)
- {
- this->m_dwOffsetLow += dwLen;
- }
- else
- {
- this->m_dwOffsetHigh++;//高位加1
- this->m_dwOffsetLow += (dwLen - 0xFFFFFFFF);
- }
- return WriteFile(this->m_Handle, this->m_Buffer, dwLen,
- &m_dwByteWrittern, m_pOverLapped);
- }
- DWORD CBufferLog::GetPosition(DWORD &High32)
- {
- this->Flush();
- High32 = 0;
- return SetFilePointer(this->m_Handle, 0, (PLONG)&High32, FILE_CURRENT);
- }
===================================
非注明转载的文章和blog在未特殊声明情况下一般为本人原创或整理,
原创文章版权本人(lonefox)所有;转载文章版权归原作者所有;
http://blog.youkuaiyun.com/boythl
欢迎转载,但请注明出处,保留作者和版权信息。
===================================