common_mq共享模块

一.宏日志类logger.hpp

#ifndef __M_LOG_H__
#define __M_LOG_H__
#include <iostream>
#include <ctime>

#define DBG_LEVEL 0
#define INF_LEVEL 1
#define ERR_LEVEL 2
#define DEFAULT_LEVEL DBG_LEVEL
#define LOG(lev_str, level, format, ...) {\
    if (level >= DEFAULT_LEVEL) {\
        time_t t = time(nullptr);\
        struct tm* ptm = localtime(&t);\
        char time_str[32];\
        strftime(time_str, 31, "%H:%M:%S", ptm);\
        printf("[%s][%s][%s:%d]\t" format "\n", lev_str, time_str, __FILE__, __LINE__, ##__VA_ARGS__);\
    }\
}

#define DLOG(format, ...) LOG("DBG", DBG_LEVEL, format, ##__VA_ARGS__)
#define ILOG(format, ...) LOG("INF", INF_LEVEL, format, ##__VA_ARGS__)
#define ELOG(format, ...) LOG("ERR", ERR_LEVEL, format, ##__VA_ARGS__)
#endif

默认情况下依次打印 日志等级,时间,文件名,行号,并且额外提供了C风格的格式化输出。

demo:

DLOG("This is a debug message: value = %d", 42);
ILOG("This is an info message.");
ELOG("This is an error message.");
[DBG][12:34:56][main.cpp:10]    This is a debug message: value = 42
[INF][12:34:56][main.cpp:11]    This is an info message.
[ERR][12:34:56][main.cpp:12]    This is an error message.

二.公共工具类helper.hpp

SqliteHelper

   class SqliteHelper
    {
          private:
        std::string _dbfile;
        sqlite3 *_handler;
    public:
        typedef int (*SqliteCallback)(void *, int, char **, char **);
        SqliteHelper(const std::string &dbfile)
         : _dbfile(dbfile), _handler(nullptr) {}

        bool open(int safe_leve = SQLITE_OPEN_FULLMUTEX)
        {
            // int sqlite3_open_v2(const char *filename, sqlite3 **ppDb, int flags, const char *zVfs );
            int ret = sqlite3_open_v2(_dbfile.c_str(), &_handler, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | safe_leve, nullptr);
            if (ret != SQLITE_OK)
            {
                ELOG("创建/打开sqlite数据库失败: %s", sqlite3_errmsg(_handler));
                return false;
            }
            return true;
        }
        bool exec(const std::string &sql, SqliteCallback cb, void *arg)
        {
            // int sqlite3_exec(sqlite3*, char *sql, int (*callback)(void*,int,char**,char**), void* arg, char **err)
            int ret = sqlite3_exec(_handler, sql.c_str(), cb, arg, nullptr);
            if (ret != SQLITE_OK)
            {
                ELOG("%s \n语句执行失败: %s", sql.c_str(), sqlite3_errmsg(_handler));
                return false;
            }
            return true;
        }
        void close()
        {
            if (_handler)
                sqlite3_close_v2(_handler);
        }
    };

用于简化SQLite数据库的操作。SQLite是一个轻量级的数据库,它将整个数据库存储在一个单一的磁盘文件中,不需要一个独立的服务器进程。
这个类封装了一些基本的SQLite操作,使得在C++程序中使用SQLite数据库更加方便。

std::string _dbfile:用于存储  数据库文件的路径+数据库名称

sqlite3 *_handler是一个指向 sqlite3 结构的指针,用于操作数据库(管理句柄)

bool open(int safe_level = SQLITE_OPEN_FULLMUTEX):用于打开或创建数据库。默认使用 SQLITE_OPEN_FULLMUTEX 标志来确保线程安全。
bool exec(const std::string &sql, SqliteCallback cb, void *arg):用于执行SQL语句。可以传递一个回调函数和一个参数(一般用来保存查询结果)给这个函数。

StrHelper

 class StrHelper
    {
    public:
        static size_t split(const std::string &str, const std::string &sep, std::vector<std::string> &ret)
        {
            size_t start = 0;
            size_t pos = std::string::npos;
            // 123...123.
            while ((pos = str.find(sep, start)) != std::string::npos) // 没有找到分隔符
            {
                if (pos == start)
                {
                    start = pos + sep.size();
                    continue;
                }
                ret.push_back(std::move(str.substr(start, pos - start)));
                start = pos + sep.size();
            }

            // 处理最后一个分隔符后的数据
            if (start < str.size())
                ret.push_back(std::move(str.substr(start)));

            return ret.size();
        }
    };
  • static size_t split(const std::string &str, const std::string &sep, std::vector<std::string> &ret):这是一个静态成员函数,用于分割字符串。它接收三个参数:
    • const std::string &str:要分割的原始字符串。
    • const std::string &sep:分隔符字符串。
    • std::vector<std::string> &ret:用于存储分割结果的字符串向量。

函数逻辑

  1. size_t start = 0;:定义一个变量 start 来记录当前搜索的起始位置。

  2. size_t pos = std::string::npos;:定义一个变量 pos 来存储分隔符的位置,初始值为 std::string::npos,表示未找到分隔符。

  3. while ((pos = str.find(sep, start)) != std::string::npos):使用 find 方法循环查找字符串 str 中的分隔符 sep。如果找到了分隔符,pos 将被更新为分隔符的索引。

  4. if (pos == start):如果分隔符紧跟在 start 之后,跳过这个空字符串,更新 start 为分隔符之后的位置,并继续循环(跳过连续分隔符)

  5. ret.push_back(std::move(str.substr(start, pos - start)));:将从 startpos 的子字符串添加到结果向量 ret 中。使用 std::move 可以避免复制,提高效率。

  6. start = pos + sep.size();:更新 start 为下一个搜索的起始位置。

  7. if (start < str.size()):处理最后一个分隔符之后剩余的字符串部分,将其添加到结果向量中。

  8. return ret.size();:返回分割后得到的子字符串数量。

demo

std::vector<std::string> result;
size_t count = StrHelper::split("one,two,three,four", ",", result);
for (const auto &part : result) {
    std::cout << part << std::endl;
}
// 输出:
// one
// two
// three
// four

UUIDHelper

 class UUIDHelper
    {
    public:
        //  8-4-4----4-12
        static std::string uuid()
        {
            // 重载了operator()
            // 1.用硬件随机数作为随机数种子
            // 2.生成伪随机数[0,255]
            // 3.转化为16进制,并用-分割
            // 4.生成16位的序号,便于观察
            std::random_device rd;
            std::mt19937_64 mt(rd()); // 伪随机数
            std::uniform_int_distribution<int> distribution(0, 255);

            std::stringstream sstream;
            for (int i = 0; i < 8; ++i)
            {
                int rnum = distribution(mt);
                sstream << std::setw(2) << std::setfill('0') << std::hex << rnum;
                if (i == 3 || i == 5 || i == 7)
                    sstream << "-";
            }

            static std::atomic<int> cnt(1); // 全局唯一
            // 每次获取uuid,cnt都自增1
            size_t num = cnt.fetch_add(1); // 8字节,每次取出1字节
            for (int i = 7; i >= 0; --i)
            {
                sstream << std::setw(2) << std::setfill('0') << std::hex << ((num >> i * 8) & 0xff);
                if (i == 6)
                    sstream << "-";
            }

            return sstream.str();
        }
    };

随机数种子和伪随机数:

使用 std::random_device 作为随机数种子,确保每次生成的UUID都是不同的。
使用 std::mt19937_64 作为伪随机数生成器,它基于Mersenne Twister算法。
生成随机数:

使用 std::uniform_int_distribution<int> 来生成一个在0到255范围内的均匀分布的整数。
字符串流操作:使用 std::stringstream 来构建最终的UUID字符串。
生成UUID的主体部分:

循环8次,每次生成一个两位的16进制数,并根据UUID的格式在第4、6、8位后添加短横线。
全局计数器:

使用 std::atomic<int> 定义一个全局计数器 cnt,确保即使在多线程环境下也能安全地递增。
生成UUID的序号部分:

每次调用 uuid 函数时,cnt 递增,并将其转换为16进制形式,然后插入到UUID字符串的最后12位。
返回结果:

最终的UUID字符串通过 sstream.str() 获取,并作为函数的返回值。

FileHelper

   class FileHelper
    {
    private:
        std::string _filename;

    public:
        FileHelper(const std::string &filename) : _filename(filename) {}

        bool exists()
        {
            struct stat st;
            int ret = stat(_filename.c_str(), &st);
            if (ret < 0)
            {
                ELOG("%s 该文件/目录不存在", _filename.c_str());
                return false;
            }
            return true;
        }
        size_t size()
        {
            struct stat st;
            int ret = stat(_filename.c_str(), &st);
            if (ret < 0)
            {
                ELOG("%s 文件不存在", _filename.c_str());
                return 0;
            }
            return st.st_size;
        }
        bool read(std::string &text)
        {
            size_t sz = size();
            text.resize(sz);
            return read(&text[0], 0, sz);
        }
        bool read(char *buffer, size_t offset, size_t len)
        {
            // 1.打开文件
            // 2.调整偏移量
            // 3.读取数据
            // 4.关闭文件
            std::ifstream ifs(_filename, std::ios::binary | std::ios::in);
            if (!ifs.is_open())
            {
                ELOG("%s 打开文件失败", _filename.c_str());
                return false;
            }
            ifs.seekg(offset, std::ios::beg);
            ifs.read(buffer, len);
            if (!ifs.good())
            {
                ELOG("%s 文件读取失败", _filename.c_str());
                ifs.close();
                return false;
            }
            ifs.close();
            return true;
        }
        bool write(const std::string &text)
        {
            return write(text.c_str(), 0, text.size());
        }
        bool write(const char *buf, size_t offset, size_t len)
        {
            std::fstream fs(_filename, std::ios::binary | std::ios::in | std::ios::out);
            if (!fs.is_open())
            {
                ELOG("%s 打开文件失败", _filename.c_str());
                return false;
            }
            fs.seekp(offset, std::ios::beg);
            fs.write(buf, len);
            if (!fs.good())
            {
                ELOG("%s 文件写入失败", _filename.c_str());
                fs.close();
                return false;
            }
            fs.close();
            return true;
        }
        bool rename(const std::string &nname)
        {
            return (::rename(_filename.c_str(), nname.c_str()) == 0);
        }
        //---------------静态成员函数,创建/移除 目录和文件---------------
        static bool createFile(const std::string &filename)
        {
            std::ofstream ofs(filename.c_str(), std::ios::binary | std::ios::out | std::ios::app);
            if (!ofs.is_open())
            {
                ELOG("%s 打开文件失败", filename.c_str());
                return false;
            }
            ofs.close();
            return true;
        }
        static bool removeFile(const std::string &filename)
        {
            int ret = ::remove(filename.c_str());
            if (ret < 0 && errno != ENOENT)
            {
                ELOG("%s 删除文件失败", filename.c_str());
                return false;
            }
            return true;
        }

        static bool createDir(const std::string &path)
        {
            //"aaa/bbb/ccc/ddd" 先依次创建上级目录
            size_t begin = 0, pos = 0;
            while (pos = path.find('/', begin))
            {
                if (pos == std::string::npos)
                {
                    std::string dir = path.substr(0);
                    ::mkdir(dir.c_str(), 0775);
                    return true;
                }
                std::string dir = path.substr(0, pos);
                int ret = ::mkdir(dir.c_str(), 0775);
                if (ret < 0 && errno != EEXIST)
                {
                    ELOG("%s 创建目录失败", dir.c_str());
                    ELOG("错误原因: %s", strerror(errno));
                    return false;
                }
                begin = pos + 1;
            }
            return true;
        }
        static bool removeDir(const std::string &path)
        {
            std::string str = " rm -rf " + path;
            return system(str.c_str()) == 0;
        }
        static std::string getParentDirName(const std::string &filename)
        {
            size_t pos = filename.rfind('/');
            if (pos == std::string::npos)
            {
                return "./";
            }
            std::string path = filename.substr(0, pos);
            return path;
        }
    };

封装了一些常用的文件操作,如检查文件是否存在、获取文件大小、读取和写入文件内容、重命名文件、以及创建和删除文件和目录等。

成员函数

  • bool exists():检查文件或目录是否存在。
  • size_t size():获取文件的大小。
  • bool read(std::string &text):读取整个文件内容到字符串。
  • bool read(char *buffer, size_t offset, size_t len):从文件中读取指定长度的数据到缓冲区。
  • bool write(const std::string &text):将字符串内容写入文件。
  • bool write(const char *buf, size_t offset, size_t len):将缓冲区的内容写入文件的指定位置。
  • bool rename(const std::string &nname):重命名文件。

静态成员函数

  • static bool createFile(const std::string &filename):创建一个新文件。
  • static bool removeFile(const std::string &filename):删除一个文件。
  • static bool createDir(const std::string &path):递归创建目录。
  • static bool removeDir(const std::string &path):删除目录及其内容。
  • static std::string getParentDirName(const std::string &filename):获取文件的父目录名称。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值