C++类设计:一个不同版本的日志类(完整源码)

初级代码游戏的专栏介绍与文章目录-CSDN博客

我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。

这些代码大部分以Linux为目标但部分代码是纯C++的,可以在任何平台上使用。

 


        如何设计日志类请看:C++类设计:设计一个日志类(源码)_初级代码游戏的博客-CSDN博客        

        这个版本有些不同,支持输出到编辑框、文件和VS的输出窗口,基本结构完全相同。

目录

一、效果

二、完整源码

三、详解

3.1 输出到VS输出窗口

3.2 输出到编辑框

3.3 输出到文件


一、效果

        VS2017,MFC,UNICODE字符集。

        输出到编辑框:

        自动向下滚动,编辑框必须是多行的。

         输出到VS输出窗口(调试模式):

二、完整源码

        头文件:

//common.h

#pragma once
#include <sstream>
#include <map>
using namespace std;

extern CEdit* pGlobalLogWnd;

class CStringConvert
{
public:
	static string WStringToString(wstring const& wstr)
	{
		size_t buflen = wstr.size() * sizeof(wchar_t) + 1;
		char* buf = new char[buflen];
		WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, buf, (int)buflen, NULL, 0);
		string ret = buf;
		delete[] buf;
		return ret;
	}
	static wstring StringToWString(string const& str)
	{
		//返回接受字符串所需缓冲区的大小,已经包含字符结尾符'\0'
		int iSize = MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, NULL, 0);
		wchar_t* buf = new wchar_t[iSize * sizeof(wchar_t)];
		MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, buf, iSize);
		wstring ret = buf;
		delete[] buf;
		return ret;
	}
};

class CLog
{
private:
	HANDLE hFile = 0;//输出文件

	stringstream m_buf;//一条信息
	CString m_file;//产生日志的文件名
	int m_line;//产生日志的行号

	int m_limit_text = UINT_MAX;//最大长度,编辑框的默认值大概是几十K,需要设置得更大
	
	void end(char const* logtype)
	{
		CString str;

		//格式化信息
		str += logtype;
		str += ":";
		str += m_buf.str().c_str();
		if (m_file.GetLength() > 0)
		{
			CString line;
			line.Format(TEXT("%d"), m_line);
			str += TEXT(" [From ") + m_file + TEXT(":") + line + TEXT("]");
		}
		str += "\r\n";

		//输出到VS信息窗口
		OutputDebugString(str);

		//输出到文件
		if (hFile)
		{
			DWORD dwCount;
			string mbcs_string = CStringConvert::WStringToString(str.GetString());
			WriteFile(hFile, mbcs_string.c_str(), (DWORD)mbcs_string.size(), &dwCount, 0);
		}
		
		//输出到编辑框
		if (pGlobalLogWnd && ::IsWindow(pGlobalLogWnd->m_hWnd))
		{
			pGlobalLogWnd->SetLimitText(m_limit_text);
			while (pGlobalLogWnd->GetWindowTextLength() >= m_limit_text)
			{
				//pGlobalLogWnd->SetSel(0, mag_size.begin()->second + 2);
				//pGlobalLogWnd->ReplaceSel(TEXT(""));
				//mag_size.erase(mag_size.begin());
				pGlobalLogWnd->SetWindowText(TEXT(""));
			}

			int nLength = pGlobalLogWnd->GetWindowTextLength();
			pGlobalLogWnd->SetSel(nLength, nLength);
			pGlobalLogWnd->ReplaceSel(str);
			pGlobalLogWnd->LineScroll(pGlobalLogWnd->GetLineCount());
		}
		else
		{
			OutputDebugString(TEXT("日志窗口失效\r\n"));
		}
		
		//清除缓存的信息
		m_buf.str("");
		m_file = "";
		m_line = 0;
	}
public:
	CLog()
	{
		wchar_t pszPathName[2048];
		GetModuleFileName(NULL, pszPathName, 2048);
		StrCat(pszPathName, TEXT(".log"));
		hFile = CreateFile(pszPathName, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL
			, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
		if (INVALID_HANDLE_VALUE == hFile)
		{
			MessageBox(NULL,TEXT("创建或打开日志文件失败"),TEXT("出错"),0);
		}
	}
	~CLog()
	{
		if (hFile)CloseHandle(hFile);
	}
	void set_LimitText(int n) { m_limit_text = n; }
	struct CLog_ende
	{};
	struct CLog_endi
	{};
	struct CLog_endd
	{};
	CLog& SetPos(char const * file, int line)
	{
		m_file = file;
		m_line = line;
		return *this;
	}
	template<typename T>
	CLog& operator<<(T const& data)
	{
		m_buf << data;
		return *this;
	}
	CLog& operator<<(CLog_ende const& data)
	{
		end("错误");
		return *this;
	}
	CLog& operator<<(CLog_endi const& data)
	{
		end("信息");
		return *this;
	}
	CLog& operator<<(CLog_endd const& data)
	{
		end("调试");
		return *this;
	}
	CLog& operator<<(CString const& data)
	{
		return operator<<(data.GetString());
	}
	CLog& operator<<(wchar_t const* data)
	{
		return operator<<(CStringConvert::WStringToString(wstring(data)));
	}
	CLog& operator<<(RECT const& data)
	{
		return *this << "{" << data.left << "," << data.top << "," << data.right << "," << data.bottom << "}";
	}
};

extern bool G_IS_DEBUG;
extern CLog gloablLog;
#define thelog (gloablLog.SetPos( __FILE__ , __LINE__))
#define debuglog if(G_IS_DEBUG)gloablLog.SetPos( __FILE__ , __LINE__)
extern CLog::CLog_ende ende;
extern CLog::CLog_endi endi;
extern CLog::CLog_endd endd;

        源文件:

#include "pch.h"
#include "common.h"

CEdit* pGlobalLogWnd = nullptr;

bool G_IS_DEBUG = false;
CLog gloablLog;
CLog::CLog_ende ende;
CLog::CLog_endi endi;
CLog::CLog_endd endd;

        使用:

	//设置编辑框最大长度
    gloablLog.set_LimitText(1024 * 1024);
    //设置编辑框指针,不设置则不输出到编辑框
	pGlobalLogWnd = &this->m_LogWnd;
    //打开调试开关,否则debuglog不输出
	G_IS_DEBUG = true;

    //输入出日志:
    thelog<<a<<b<<c<<endi;
    thelog<<a<<b<<c<<ende;
    thelog<<a<<b<<c<<endd;
    debuglog<<a<<b<<c<<endi;
    debuglog<<a<<b<<c<<ende;
    debuglog<<a<<b<<c<<endd;

三、详解

3.1 输出到VS输出窗口

        在调试模式下可以直接输出到VS的输出窗口,使用如下函数即可:

debugapi.h
Kernel32.lib/Kernel32.dll

void OutputDebugStringA(
  [in, optional] LPCSTR lpOutputString
);

        不过如果不是调试模式就没用了。

3.2 输出到编辑框

        图形界面程序完全可以自带日志窗口,这里用了一个编辑框CEdit。用作日志的编辑框需要做一些设置:

  • 多行
  • 滚动条
  • 最大字符数大一些
  • 自动滚动

        前两个在窗体设计器设置即可,后两个靠代码:

		//输出到编辑框
		if (pGlobalLogWnd && ::IsWindow(pGlobalLogWnd->m_hWnd))
		{
			pGlobalLogWnd->SetLimitText(m_limit_text);
			while (pGlobalLogWnd->GetWindowTextLength() >= m_limit_text)
			{
				//pGlobalLogWnd->SetSel(0, mag_size.begin()->second + 2);
				//pGlobalLogWnd->ReplaceSel(TEXT(""));
				//mag_size.erase(mag_size.begin());
				pGlobalLogWnd->SetWindowText(TEXT(""));
			}

			int nLength = pGlobalLogWnd->GetWindowTextLength();
			pGlobalLogWnd->SetSel(nLength, nLength);
			pGlobalLogWnd->ReplaceSel(str);
			pGlobalLogWnd->LineScroll(pGlobalLogWnd->GetLineCount());
		}

        编辑框的修改要用ReplaceSel,不能用SetWindowText,会严重闪烁。

3.3 输出到文件

        输出到文件没什么好解释了,要注意的就是输出文件的编码,尽量用utf-8,兼容性比较好。如果输出宽字符,用记事本打开可能乱码(或许是没有添加BOM的原因,总之utf-8最简单啦)。


(这里是结束)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/509187.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

独角数卡安装前后常见问题汇总

PHP终端环境对应不上 服务器终端下执行以下命令将宝塔php版本设置为系统php-cli版本 ln -sf /www/server/php/73/bin/php /usr/bin/phpBash Copy Bash Copy 根据自己宝塔安装的php版本执行&#xff0c;不要照抄&#xff0c;这里是/php/73&#xff0c;你如果是php7.2的话就…

Vue-05

v-model 应用于其他表单元素 常见的表单元素都可以用v-model绑定关联 → 快速获取或设置表单元素的值 它会根据控件类型自动选取正确的方法来更新元素 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name…

苏州金龙助力旅游客运加速蜕变

近日&#xff0c;北京铭悦旅游客运有限公司又迎来一批苏州金龙海格纯电动客车。&#xff08;以下简称北京铭悦旅游&#xff09;总经理郭保生在车辆交付时说到&#xff0c;“为迎接强劲复苏的旅游市场&#xff0c;要求旅游客运向绿色客运转型&#xff0c;以及人民对品质生活、美…

c# 插值搜索-迭代与递归(Interpolation Search)

给定一个由 n 个均匀分布值 arr[] 组成的排序数组&#xff0c;编写一个函数来搜索数组中的特定元素 x。 线性搜索需要 O(n) 时间找到元素&#xff0c;跳转搜索需要 O(? n) 时间&#xff0c;二分搜索需要 O(log n) 时间。 插值搜索是对实例二分搜索的改进&#xff0c;…

测试Windows域控制器服务是否运行

测试Windows域控制器服务是否正常运行&#xff0c;可以通过以下几种方法&#xff1a; 检查服务状态&#xff1a; 打开“服务器管理器”&#xff08;Server Manager&#xff09;。在左侧导航栏中选择“工具”&#xff08;Tools&#xff09;&#xff0c;然后打开“服务”&#xf…

基于springboot实现在线文档管理系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现在线文档管理系统演示 摘要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;在线文档管理当然也不能排除在外。在线文档管理系统是以实际运用为开发背景&am…

语义分割——自动驾驶鱼眼数据集

一、重要性及意义 环境感知&#xff1a;语义分割技术能够精确识别道路、车辆、行人、障碍物、交通标志和信号等各种交通场景元素。这为自动驾驶系统提供了丰富的环境信息&#xff0c;有助于车辆准确理解周围环境的结构和动态变化。决策规划&#xff1a;基于语义分割的结果&…

研发设计人员能力级别定义

研发设计人员能力&级别定义 1. 源由2. 级别定义3. 级别能力3.1 助理工程师3.1.1 工作内容3.1.2 级别晋升3.1.3 详细描述 3.2 初级工程师3.2.1 工作内容3.2.2 级别晋升3.2.3 详细描述 3.3 高级工程师3.3.1 工作内容3.3.2 级别晋升3.3.3 详细描述 3.4 资深工程师3.4.1 工作内…

谈谈MVCC机制

在MySQL中&#xff0c;MVCC&#xff08;多版本并发控制&#xff09;是InnoDB存储引擎使用的并发控制机制。它提供对数据的并发访问&#xff0c;并确保多用户环境中数据的一致性和隔离性。 InnoDB通过“Undo log”存储每条记录的多个版本&#xff0c;提供历史记录供读取&#x…

java Web 辅助学习管理系统idea开发mysql数据库web结构java编程计算机网页源码maven项目

一、源码特点 java Web 辅助学习管理系统是一套完善的信息管理系统&#xff0c;结合java 开发技术和bootstrap完成本系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 前段主要技术 bootstr…

标准版IP地址证书

IP地址证书是一种网络安全工具&#xff0c;用于确保互联网通信中IP地址的所有权和真实性。它类似于为网站颁发的SSL/TLS证书&#xff0c;但专门针对IP地址。这种证书由受信任的第三方机构&#xff08;如证书颁发机构&#xff09;签发&#xff0c;包含公钥、所有者信息和有效期。…

Python提取PDF中的表格写入Excel

目录 专栏导读库的介绍安装准备测试数据代码1、导入2、加载3、获取表格4、写入Excel完整代码总结专栏导读 🌸 欢迎来到Python办公自动化专栏—Python处理办公问题,解放您的双手 🏳️‍🌈 博客主页:请点击——>

学习Linux推荐的书籍

我记得有人曾经说过&#xff0c;征服一个男人最好的途径就是抓住他的胃。 ‍‍‍‍ 学习Linux&#xff0c;最重要的就是要先搞懂Linux是啥&#xff0c;有啥&#xff0c;为啥&#xff1f;‍‍‍‍‍‍‍‍‍‍‍‍‍ 所以&#xff0c;我推荐的第一本书就是-《Unix编程艺术》。…

vue 响应式原理 Object.defineProperty(obj,‘属性名A‘,options);

目录 self简单讲解1. 视图影响数据2. 数据影响视图3. 视图数据双向影响页面展示 百度 self 简单讲解 get和set方法是ES5中提供的&#xff0c;因为是方法&#xff0c;所以可以进行判断&#xff0c;get 一般是要通过 return 返回的&#xff1b;而 set 是设置&#xff0c;不用返回…

Nexpose v6.6.244 for Linux Windows - 漏洞扫描

Nexpose v6.6.244 for Linux & Windows - 漏洞扫描 Rapid7 Vulnerability Management, Release Mar 27, 2024 请访问原文链接&#xff1a;https://sysin.org/blog/nexpose-6/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.o…

Python抓取京东、淘宝商品数据(属性详情,sku价格抓取)

抓取京东、淘宝等电商平台的商品数据&#xff08;包括属性详情、SKU价格等&#xff09;通常涉及到网络爬虫技术。这些平台都有自己的反爬虫机制&#xff0c;因此抓取数据需要谨慎操作&#xff0c;避免对平台造成不必要的负担或违反其使用条款。 公共参数 名称类型必须描述key…

提升工作效率:B端工作台设计基础详解

随着互联网和信息技术的快速发展&#xff0c;越来越多的企业开始以数字化、智能化的方式管理和运营自己的业务。B端工作台设计作为企业应用的重要组成部分&#xff0c;越来越受到重视。本文将从三个方面对B端工作台设计进行全面分析。让我们看看。 1. B端工作台设计原则 B端工…

Nginx漏洞之未授权访问和源码泄漏漏洞处理

一、漏洞描述 某次安全扫描&#xff0c;发现某平台存在资源&#xff1a;未授权访问和源码泄漏&#xff1b;攻击者可能获取到网站的配置文件、敏感数据存储位置和访问凭证等信息。这意味着攻击者可以获得对网站的完全或部分控制权&#xff0c;进而进行恶意篡改、删除或添加恶意…

交换机MSTP (多生成树防环协议)基础配置

MSTP 基础配置 在所有交换机上创建 VLAN10、20、30、40、50、60、70、80&#xff0c;配置 MSTP 域 hcip&#xff0c;并创建 两个新的实例&#xff1a;Instance 1、Instance 2&#xff0c;将 VLAN10、30、50、70 映射到 Instance 1&#xff0c;将 VLAN20、40、60、80 映射到 Ins…

win11下,RTMP流媒体服务器保姆级教程

本片博客将详细介绍如何搭建一个RTMP流媒体服务器,包含源码下载&#xff0c;编译常见问题解决方法以及流媒体测试&#xff0c;最后讲解了如何利用obs软件实现推流。 服务器&#xff1a;SRS 3.0(Simple Realtime Server&#xff0c;支持RTMP、HTTP-FLV、HLS、WebRTC) 推流端&…