日志打印和实用 Helper 工具

文章目录

  • [1. 日志打印工具](#1. 日志打印工具)
  • [2. 实用 ****Helper ****工具](#2. 实用 ****Helper ****工具)
    • [2.1 sqlite 基础操作类](#2.1 sqlite 基础操作类)
    • [2.2 字符串操作类](#2.2 字符串操作类)
    • [2.3 UUID 生成器类](#2.3 UUID 生成器类)
      • [2.3.1 整体设计思路](#2.3.1 整体设计思路)
      • [2.3.2 涉及的C++类详解](#2.3.2 涉及的C++类详解)
    • [2.4 文件基础操作](#2.4 文件基础操作)
      • [2.4.1 框架](#2.4.1 框架)
      • [2.4.2 判断文件存在和大小获取](#2.4.2 判断文件存在和大小获取)
      • [2.4.3 文件读取](#2.4.3 文件读取)
      • [2.4.4 文件写入](#2.4.4 文件写入)
      • [2.4.5 文件重命名和获取父级目录](#2.4.5 文件重命名和获取父级目录)
      • [2.4.6 创建/删除文件](#2.4.6 创建/删除文件)
      • [2.4.7 创建/删除目录](#2.4.7 创建/删除目录)
      • [2.4.8 测试](#2.4.8 测试)

1. 日志打印工具

为了便于编写项目中能够快速定位程序的错误位置,因此编写一个日志打印类,进行简单的日志打印。

cpp 复制代码
#include <iostream>
#include <ctime>

//封装一个日志宏,通过日志宏进行日志的打印,在打印的信息前带有系统时间以及文件名和行号
//     [日志等级][17:26:24] [log.cpp:12] 打开文件失败! 


#define DBG_LEVEL 0
#define INF_LEVEL 1
#define ERR_LEVEL 2
#define DEFAULT_LEVEL DBG_LEVEL
#define LOG(lev_str, level, format, ...) do{\
    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__);\
    }\
}while(0)

#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__)

int main() 
{
    DLOG("Hello World");
    ILOG("Hello World");
    ELOG("Hello World");
    return 0;
}

关键实现点

  • do{...}while(0):将多条语句包装为单条语句,防止宏展开时出现问题
  • ##VA_ARGS:GCC/Clang扩展,正确处理可变参数
  • 编译时信息__FILE____LINE__是预定义的宏,记录日志位置

运行结果:

bash 复制代码
ltx@My-Xshell-8-Pro-Max-Ultra:~/rabbit-mq/mqdemo/mqlog$ g++ log.cpp -o log
ltx@My-Xshell-8-Pro-Max-Ultra:~/rabbit-mq/mqdemo/mqlog$ ./log
[DBG][22:02:20][log.cpp:28]     Hello World
[INF][22:02:20][log.cpp:29]     Hello World
[ERR][22:02:20][log.cpp:30]     Hello World

2. 实用 Helper工具

Helper 工具类中要完成的是项目中需要的一些辅助零碎的功能代码实现,其中包括文件的基础操作,字符串的额外操作等在项目中用到的零碎功能。

2.1 sqlite 基础操作类

  1. 判断库是否存在
  2. 创建并打开库 / 关闭库 / 删除库
  3. 启动 / 提交 / 回滚事务
  4. 执行语句

前面在介绍sqlite3的时候我们就已经封装过了,这里我们直接拷贝过来,加上我们上面实现的一个简单日志宏

cpp 复制代码
namespace rabbitmq
{
    class SqliteHelper
    {
    public:
        typedef int (*SqliteCallback)(void *, int, char **, char **);

        SqliteHelper(const std::string &dbfile) : _dbfile(dbfile), _handler(nullptr) {}

        bool open(int safe_level = SQLITE_OPEN_FULLMUTEX)
        {
            int ret = sqlite3_open_v2(_dbfile.c_str(), &_handler, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | safe_level, nullptr);
            if (ret != SQLITE_OK)
            {
                DLOG("创建/打开sqlite数据库失败: %s", sqlite3_errmsg(_handler));
                return false;
            }
            return true;
        }
        bool exec(const std::string &sql, SqliteCallback cb, void *arg)
        {
            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);
        }

    private:
        std::string _dbfile;
        sqlite3 *_handler;
    };
}

2.2 字符串操作类

提供字符串分割功能

cpp 复制代码
#include <iostream>
#include <vector>
#include <string>

size_t split(const std::string &str, const std::string &sep, std::vector<std::string>& result)
{
    // news....music.#.pop
    // 分割的思想:
    //  1. 从0位置开始查找指定字符的位置, 找到之后进行分割
    //  2. 从上次查找的位置继续向后查找指定字符
    size_t pos = 0, idx = 0;
    while (idx < str.size())
    {
        pos = str.find(sep, idx);
        if (pos == std::string::npos)
        {
            result.push_back(str.substr(idx));
            return result.size();
        }

        //pos == idx 代表两个分隔符之间没有数据,或者说查找起始位置就是分隔符
        if (idx == pos)
        {
            idx = pos + sep.size();
            continue;
        }
        result.push_back(str.substr(idx, pos - idx));
        idx = pos + sep.size();
    }
    return result.size();
}

int main()
{
    std::string str = "...news....music.#.pop...";
    std::vector<std::string> arry;
    int n = split(str, ".", arry);
    for (auto &s : arry) {
        std::cout << s << std::endl;
    }
    return 0;
}

运行结果:

bash 复制代码
ltx@My-Xshell-8-Pro-Max-Ultra:~/rabbit-mq/mqdemo/split$ g++ split.cpp -o split
ltx@My-Xshell-8-Pro-Max-Ultra:~/rabbit-mq/mqdemo/split$ ./split
news
music
#
pop

2.3 UUID 生成器类

UUID(Universally Unique Identifier), 也叫通用唯一识别码,通常由 32 位 16 进制数字字符组成。

UUID 的标准型式包含 32 个 16 进制数字字符,以连字号分为五段,形式为 8-4-4-4-12的 32 个字符,如:550e8400-e29b-41d4-a716-446655440000。

在这里,uuid 生成,我们采用生成 8 个随机数字,加上 8 字节序号,共 16 字节数据生成 32 位 16 进制字符的组合形式来确保全局唯一的同时能够根据序号来分辨数据。

2.3.1 整体设计思路

  1. UUID格式设计
plain 复制代码
格式:xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx
      ↑↑↑↑↑↑↑↑ ↑↑↑↑ ↑↑↑↑ ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
      8字节随机数   				8字节序列号
      16个十六进制字符 		16个十六进制字符

注意:最后8字节序列号会是16个十六进制字符的形式,后面会拆分为4-12的格式

  1. 各部分功能
  • 前8字节(16字符):伪随机数,确保全局唯一性
  • 后8字节(16字符):原子递增序列号,便于人工识别

2.3.2 涉及的C++类详解

  1. 随机数生成相关类

std::random_device

cpp 复制代码
std::random_device rd;
  • 功能:生成真随机数的设备
  • 原理:访问硬件熵源(如CPU随机数生成器)
  • 特点:真正的随机性,但速度较慢
  • 使用场景:通常用作伪随机数生成器的种子

std::mt19937_64

cpp 复制代码
std::mt19937_64 generator(rd());
  • 功能:64位梅森旋转算法伪随机数生成器
  • 参数 :种子(seed),使用random_device生成
  • 特点
    • 周期极长:2^19937-1
    • 速度快,质量高
    • 可重复(给定相同种子产生相同序列)
  • 为什么用64位:生成64位随机数,但这里只取低8位(每个[0, 255]的随机数占8个比特位)

std::uniform_int_distribution

cpp 复制代码
std::uniform_int_distribution<int> distribution(0, 255);
  • 功能:均匀整数分布
  • 参数:范围[0, 255],对应一个字节
  • 作用:将随机数映射到指定范围
  • 为什么是0-255:每个字节用两位十六进制表示
  1. 字符串处理相关类

std::stringstream

  • 功能: 字符串流,类似stringiostream的组合
  • 优点: 可以像使用cout一样输出格式化数据
  • 用途: 构建格式化字符串

std::setw 和 std::setfill

  • std::setw(n):设置输出宽度为n个字符
  • std::setfill(ch):用字符ch填充空白
  • 作用:确保每个字节输出为两位十六进制字符
  • 示例 :数字10"0a",而不是"a"

std::hex

  • 功能:设置输出格式为十六进制
  • 示例 :十进制255→ 十六进制"ff"
  1. 并发安全相关类

std::atomic<size_t>

  • 功能:原子类型,提供线程安全的操作
  • 为什么需要:多线程环境下安全递增计数器
  • 内存序:默认使用顺序一致性(sequential consistency)

完整代码:

cpp 复制代码
#include <iostream>
#include <random>
#include <sstream>
#include <iomanip>
#include <atomic>

std::string uuid()
{
    std::random_device rd;
    // size_t num = rd(); // 生成一个机器随机数,效率较低
    // 因此解决方案,就是通过一个机器随机数作为生成伪随机数的种子
    std::mt19937_64 gernator(rd()); // 通过梅森旋转算法,生成一个伪随机数
    // 我们要生成的是8个0~255之间的数字,所以要限定数字区间
    std::uniform_int_distribution<int> distribution(0, 255);
    // 然后将生成的数字转换为16进制数字字符
    std::stringstream ss;
    for (int i = 0; i < 8; i++)
    {
        // 1. generator() 生成一个64位伪随机数
        // 2. distribution 将64位数映射到 [0, 255] 范围
        // 3. 将这个8位值格式化到字符流中
        // 4. 循环8次,重复上述过程
        ss << std::setw(2) << std::setfill('0') << std::hex << distribution(gernator);
        if (i == 3 || i == 5 || i == 7)
        {
            ss << "-";
        }
    }
    static std::atomic<size_t> seq(1); // 定义一个原子类型整数,初始化为1
    size_t num = seq.fetch_add(1);
    for (int i = 7; i >= 0; i--)
    {
        ss << std::setw(2) << std::setfill('0') << std::hex << ((num >> (i * 8)) & 0xff);
        if (i == 6)
            ss << "-";
    }
    return ss.str();
}

int main()
{
    for (int i = 0; i < 20; i++)
    {
        std::cout << uuid() << std::endl;
    }
    return 0;
}

运行结果:

bash 复制代码
ltx@My-Xshell-8-Pro-Max-Ultra:~/rabbit-mq/mqdemo/random$ make
g++ -std=c++11 random.cpp -o random
ltx@My-Xshell-8-Pro-Max-Ultra:~/rabbit-mq/mqdemo/random$ ./random
2a3ae827-00e8-e827-0000-000000000001
f7f38a2f-9427-ce05-0000-000000000002
bf811909-0f0a-c0db-0000-000000000003
24038fb8-2727-f4d1-0000-000000000004
b9785090-3120-41d7-0000-000000000005
5d1c925e-eff5-0ea7-0000-000000000006
baefecec-508e-e79c-0000-000000000007
0e3de1ef-b737-b439-0000-000000000008
e58b9125-dea4-5631-0000-000000000009
706e9f12-f4a3-26e1-0000-00000000000a
d33c3d33-2417-5cb5-0000-00000000000b
dde52cd3-dcd5-cd4c-0000-00000000000c
0a6d7521-f24e-2bdd-0000-00000000000d
37248dac-e0ef-329f-0000-00000000000e
29d561e4-0d96-6ef7-0000-00000000000f
056dce47-d000-4620-0000-000000000010
6dc7ba41-d0e8-0284-0000-000000000011
3080b820-551a-89bc-0000-000000000012
ff5c156d-0df3-e39b-0000-000000000013
65003c52-8274-fa97-0000-000000000014

2.4 文件基础操作

大致有以下基础操作:

  • 文件是否存在判断
  • 文件大小获取
  • 文件读/写
  • 文件创建/删除
  • 目录创建/删除

2.4.1 框架

cpp 复制代码
	class FileHelper
    {
    public:
        FileHelper(const std::string& filename):_filename(filename)
        {}
        bool exists();
        size_t size();
        // 重载从offet位置开始读len个字节数据
        bool read(char *body, size_t offset, size_t len);
        bool read(std::string& body);
        // 重载从offet位置开始写len个字节数据
        bool write(const char *body, size_t offset, size_t len);
        bool write(const std::string& body);

        // 文件重命名
        bool rename(const std::string &nname);
        // 获取文件的父级目录
        static std::string parentDirectory(const std::string &filename);
        // 创建/删除文件
        static bool createFile(const std::string &filename);
        static bool removeFile(const std::string &filename);
        // 创建/删除目录
        static bool createDirectory(const std::string &path);
        static bool removeDirectory(const std::string &path);
    private:
        std::string _filename;
    };

2.4.2 判断文件存在和大小获取

怎么判断文件是否存在呢?

access系统调用可以判断文件是否存在,它通过检查文件的访问权限来实现。使用F_OK标志可以专门测试文件是否存在。例如,access("file.txt", F_OK)会返回0如果文件存在,否则返回-1并设置errno。

cpp 复制代码
#include <unistd.h>
int access(const char *pathname, int mode);

但是这里不推荐,因为该系统调用跨平台性不太行

stat() 是更好的选择,具有更好的跨平台兼容性:

cpp 复制代码
#include <sys/stat.h>   // 主要头文件
#include <sys/types.h>  // 包含各种数据类型
#include <unistd.h>     // 可选的POSIX标准头文件

int stat(const char *pathname, struct stat *statbuf);
int fstat(int fd, struct stat *statbuf);
int lstat(const char *pathname, struct stat *statbuf); // 不跟随符号链接

功能

  • stat()函数通过路径名pathname获取文件的状态信息,并保存在statbuf指向的结构体中。
  • fstat()函数通过文件描述符fd获取文件的状态信息。
  • lstat()函数与stat()类似,但是当文件是符号链接时,lstat()返回的是符号链接本身的状态信息,而不是链接指向的文件的状态信息。

参数

  • pathname: 文件路径名
  • fd: 文件描述符
  • statbuf: 指向struct stat结构体的指针,用于保存获取到的文件状态信息。

返回值

  • 成功时返回0,失败时返回-1,并设置errno。

错误

  • 常见的错误包括:文件不存在(ENOENT)、权限不足(EACCES)等。

struct stat 结构体成员

cpp 复制代码
struct stat {
    dev_t     st_dev;         /* 包含文件的设备ID */
    ino_t     st_ino;         /* 索引节点号(inode number)*/
    mode_t    st_mode;        /* 文件类型和模式(权限)*/
    nlink_t   st_nlink;       /* 硬链接数 */
    uid_t     st_uid;         /* 所有者的用户ID */
    gid_t     st_gid;         /* 所有者的组ID */
    dev_t     st_rdev;        /* 设备ID(如果是特殊文件)*/
    off_t     st_size;        /* 文件大小,以字节为单位 */
    blksize_t st_blksize;     /* 文件系统I/O的块大小 */
    blkcnt_t  st_blocks;      /* 分配给文件的512字节块的数量 */

    /* 以下成员的时间戳以秒为单位,从1970-01-01 00:00:00 UTC开始 */
    time_t    st_atime;       /* 最后访问时间 */
    time_t    st_mtime;       /* 最后修改时间 */
    time_t    st_ctime;       /* 最后状态改变时间 */
};

所以,判断文件存在和获取文件大小的操作是类似的,代码如下:

cpp 复制代码
		bool exists()
        {
            struct stat st;
            return (stat(_filename.c_str(), &st) == 0);
        }

        size_t size()
        {
            struct stat st;
            int ret = stat(_filename.c_str(), &st);
            if(ret < 0)
            {
                return 0;
            }
            return st.st_size;
        }

2.4.3 文件读取

cpp 复制代码
		// 重载从offet位置开始读len个字节数据到body中
        bool read(char *body, size_t offset, size_t len)
        {
            // 1. 打开文件
            std::ifstream ifs(_filename, std::ios::binary | std::ios::in);
            if(ifs.is_open() == false)
            {
                ELOG("%s 文件打开失败!", _filename.c_str());
                return false;
            }
            //2. 跳转文件读写位置
            ifs.seekg(offset, std::ios::beg);
            //3. 读取文件数据
            ifs.read(body, len);
            if(ifs.good() == false)
            {
                ELOG("%s 文件读取数据失败!", _filename.c_str());
                ifs.close();
                return false;
            }
			//4. 关闭文件
            ifs.close();
            return true;
        }
        bool read(std::string& body)
        {
            //获取文件大小,根据文件大小调整body的空间
            size_t fsize = this->size();
            body.resize(fsize);
            return read(&body[0], 0, fsize);
        }

2.4.4 文件写入

cpp 复制代码
		// 重载从offet位置开始写入body的len个字节数据
        bool write(const char *body, size_t offset, size_t len)
        {
            // 1. 打开文件
            std::fstream fs(_filename, std::ios::binary | std::ios::in | std::ios::out);
            if(fs.is_open() == false)
            {
                ELOG("%s 文件打开失败!", _filename.c_str());
                return false;
            }
            //2. 跳转文件指定位置
            fs.seekp(offset, std::ios::beg);
            //3. 写入文件数据
            fs.write(body, len);
            if(fs.good() == false)
            {
                ELOG("%s 文件写入数据失败!", _filename.c_str());
                fs.close();
                return false;
            }
            //4. 关闭文件
            fs.close();
            return true;
        }
        bool write(const std::string& body)
        {
            return write(body.c_str(), 0, body.size());
        }

2.4.5 文件重命名和获取父级目录

cpp 复制代码
		// 文件重命名
        bool rename(const std::string &nname)
        {
            return (::rename(_filename.c_str(), nname.c_str()) == 0);
        }
        // 获取文件的父级目录
        static std::string parentDirectory(const std::string &filename)
        {
            // /aaa/bb/ccc/ddd/test.txt
            size_t pos = filename.find_last_of("/");
            if (pos == std::string::npos) {
                // test.txt
                return "./";
            }
            std::string path = filename.substr(0, pos);
            return path;
        }

2.4.6 创建/删除文件

cpp 复制代码
		// 创建/删除文件
        static bool createFile(const std::string &filename)
        {
            std::fstream ofs(filename, std::ios::binary | std::ios::out); 
            if (ofs.is_open() == false) 
            {
                ELOG("%s 文件打开失败!", filename.c_str());
                return false;
            }
            ofs.close();
            return true;
        }
        static bool removeFile(const std::string &filename)
        {
            return (::remove(filename.c_str()) == 0);
        }

2.4.7 创建/删除目录

cpp 复制代码
		// 创建/删除目录
        static bool createDirectory(const std::string &path)
        {
            //  aaa/bbb/ccc    cccc
            // 在多级路径创建中,我们需要从第一个父级目录开始创建
            size_t pos = 0, idx = 0;
            while(idx < path.size())
            {
                pos = path.find("/", idx);
                if(pos == std::string::npos)
                {
                    return (mkdir(path.c_str(), 0775) == 0);
                }
                std::string subpath = path.substr(0, pos);
                int ret = mkdir(subpath.c_str(), 0775);
                if(ret != 0 && errno != EEXIST)
                {
                    ELOG("创建目录 %s 失败: %s", subpath.c_str(), strerror(errno));
                    return false;
                }
                idx = pos + 1;
            }
            return true;
        }
        static bool removeDirectory(const std::string &path)
        {
            // rm -rf path
            // system()
            std::string cmd = "rm -rf " + path;
            return (system(cmd.c_str()) != -1);
        }

我们这里删除目录直接调用系统命令rm -rf来完成,这样比较方便简单


2.4.8 测试

  1. 先来测试一下判断文件存在和获取文件大小的接口
cpp 复制代码
#include "../mqcommon/helper.hpp"

int main()
{
    rabbitmq::FileHelper helper("../mqcommon/logger.hpp");
    DLOG("是否存在:%d", helper.exists());
    DLOG("文件大小:%ld", helper.size());

    return 0;
}

运行结果:

bash 复制代码
ltx@My-Xshell-8-Pro-Max-Ultra:~/rabbit-mq/mqtest$ make
g++ -std=c++11 mq_filetest.cpp -o mq_filetest
ltx@My-Xshell-8-Pro-Max-Ultra:~/rabbit-mq/mqtest$ ./mq_filetest
[DBG][01:25:21][mq_filetest.cpp:6]      是否存在:1
[DBG][01:25:21][mq_filetest.cpp:7]      文件大小:748
ltx@My-Xshell-8-Pro-Max-Ultra:~/rabbit-mq/mqtest$ ll ../mqcommon/
total 24
drwxrwxr-x  2 ltx ltx 4096 Jan 22 22:13 ./
drwxrwxr-x 10 ltx ltx 4096 Jan 23 16:37 ../
-rw-rw-r--  1 ltx ltx 9129 Jan 24 01:21 helper.hpp
-rw-rw-r--  1 ltx ltx  748 Jan 22 22:06 logger.hpp

logger.hpp文件存在返回了true,同时文件大小也正确

  1. 再来测试一下创建目录和创建文件,以及获取上级目录
cpp 复制代码
int main()
{
    // rabbitmq::FileHelper helper("../mqcommon/logger.hpp");
    // DLOG("是否存在:%d", helper.exists());
    // DLOG("文件大小:%ld", helper.size());

    rabbitmq::FileHelper tmp_helper("./aaa/bbb/ccc/tmp.hpp");
    if (tmp_helper.exists() == false) {
        std::string path = rabbitmq::FileHelper::parentDirectory("./aaa/bbb/ccc/tmp.hpp");
        if (rabbitmq::FileHelper(path).exists() == false) {
            rabbitmq::FileHelper::createDirectory(path);
        }
        rabbitmq::FileHelper::createFile("./aaa/bbb/ccc/tmp.hpp");
    }

    return 0;
}

运行结果:

bash 复制代码
ltx@My-Xshell-8-Pro-Max-Ultra:~/rabbit-mq/mqtest$ make
g++ -std=c++11 mq_filetest.cpp -o mq_filetest
ltx@My-Xshell-8-Pro-Max-Ultra:~/rabbit-mq/mqtest$ ./mq_filetest
ltx@My-Xshell-8-Pro-Max-Ultra:~/rabbit-mq/mqtest$ ls
aaa  Makefile  mq_filetest  mq_filetest.cpp
ltx@My-Xshell-8-Pro-Max-Ultra:~/rabbit-mq/mqtest$ ls aaa/bbb/ccc
tmp.hpp
  1. 测试读写接口

先来测试一下全部读写

cpp 复制代码
int main()
{
    rabbitmq::FileHelper helper("../mqcommon/logger.hpp");
    DLOG("是否存在:%d", helper.exists());
    DLOG("文件大小:%ld", helper.size());

    rabbitmq::FileHelper tmp_helper("./aaa/bbb/ccc/tmp.hpp");
    if (tmp_helper.exists() == false) {
        std::string path = rabbitmq::FileHelper::parentDirectory("./aaa/bbb/ccc/tmp.hpp");
        if (rabbitmq::FileHelper(path).exists() == false) {
            rabbitmq::FileHelper::createDirectory(path);
        }
        rabbitmq::FileHelper::createFile("./aaa/bbb/ccc/tmp.hpp");
    }

    std::string body;
    helper.read(body);
    tmp_helper.write(body);
    
    return 0;
}

运行结果:

再来测试一下重载的读写接口

cpp 复制代码
int main()
{
    // rabbitmq::FileHelper helper("../mqcommon/logger.hpp");
    // DLOG("是否存在:%d", helper.exists());
    // DLOG("文件大小:%ld", helper.size());

    // rabbitmq::FileHelper tmp_helper("./aaa/bbb/ccc/tmp.hpp");
    // if (tmp_helper.exists() == false) {
    //     std::string path = rabbitmq::FileHelper::parentDirectory("./aaa/bbb/ccc/tmp.hpp");
    //     if (rabbitmq::FileHelper(path).exists() == false) {
    //         rabbitmq::FileHelper::createDirectory(path);
    //     }
    //     rabbitmq::FileHelper::createFile("./aaa/bbb/ccc/tmp.hpp");
    // }

    // std::string body;
    // helper.read(body);
    // tmp_helper.write(body);
    rabbitmq::FileHelper tmp_helper("./aaa/bbb/ccc/tmp.hpp");
    char str[16] = {0};
    tmp_helper.read(str, 8, 11);
    DLOG("[%s]", str);
    tmp_helper.write("12345678901", 8, 11);
   
    return 0;
}

运行结果:

  1. 测试文件重命名
cpp 复制代码
int main()
{
    // rabbitmq::FileHelper helper("../mqcommon/logger.hpp");
    // DLOG("是否存在:%d", helper.exists());
    // DLOG("文件大小:%ld", helper.size());

    // rabbitmq::FileHelper tmp_helper("./aaa/bbb/ccc/tmp.hpp");
    // if (tmp_helper.exists() == false) {
    //     std::string path = rabbitmq::FileHelper::parentDirectory("./aaa/bbb/ccc/tmp.hpp");
    //     if (rabbitmq::FileHelper(path).exists() == false) {
    //         rabbitmq::FileHelper::createDirectory(path);
    //     }
    //     rabbitmq::FileHelper::createFile("./aaa/bbb/ccc/tmp.hpp");
    // }

    // std::string body;
    // helper.read(body);
    // tmp_helper.write(body);
    rabbitmq::FileHelper tmp_helper("./aaa/bbb/ccc/tmp.hpp");
    // char str[16] = {0};
    // tmp_helper.read(str, 8, 11);
    // DLOG("[%s]", str);
    // tmp_helper.write("12345678901", 8, 11);
    tmp_helper.rename("./aaa/bbb/ccc/test.hpp");

    return 0;
}

运行结果:

  1. 测试删除目录和文件
cpp 复制代码
#include "../mqcommon/helper.hpp"

int main()
{
    // rabbitmq::FileHelper helper("../mqcommon/logger.hpp");
    // DLOG("是否存在:%d", helper.exists());
    // DLOG("文件大小:%ld", helper.size());

    // rabbitmq::FileHelper tmp_helper("./aaa/bbb/ccc/tmp.hpp");
    // if (tmp_helper.exists() == false) {
    //     std::string path = rabbitmq::FileHelper::parentDirectory("./aaa/bbb/ccc/tmp.hpp");
    //     if (rabbitmq::FileHelper(path).exists() == false) {
    //         rabbitmq::FileHelper::createDirectory(path);
    //     }
    //     rabbitmq::FileHelper::createFile("./aaa/bbb/ccc/tmp.hpp");
    // }

    // std::string body;
    // helper.read(body);
    // tmp_helper.write(body);
    rabbitmq::FileHelper tmp_helper("./aaa/bbb/ccc/tmp.hpp");
    // char str[16] = {0};
    // tmp_helper.read(str, 8, 11);
    // DLOG("[%s]", str);
    // tmp_helper.write("12345678901", 8, 11);
    // tmp_helper.rename("./aaa/bbb/ccc/test.hpp");

    rabbitmq::FileHelper::removeFile("./aaa/bbb/ccc/test.hpp");
    rabbitmq::FileHelper::removeDirectory("./aaa");
    return 0;
}

运行结果:

可以看到目录和文件都被删除了

相关推荐
eWidget2 小时前
面向信创环境的Oracle兼容型数据库解决方案
数据库·oracle·kingbase·数据库平替用金仓·金仓数据库
阿正的梦工坊2 小时前
使用即梦(seedream)来图生图:读取与写入飞书多维表格
数据库·飞书
Coder_Boy_2 小时前
基于SpringAI的在线考试系统-整体架构优化设计方案(续)
java·数据库·人工智能·spring boot·架构·领域驱动
云飞云共享云桌面2 小时前
推荐一些适合10个SolidWorks设计共享算力的服务器硬件配置
运维·服务器·前端·数据库·人工智能
Elastic 中国社区官方博客2 小时前
Elasticsearch:使用 Base64 编码字符串加速向量摄取
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
大模型玩家七七2 小时前
安全对齐不是消灭风险,而是重新分配风险
android·java·数据库·人工智能·深度学习·安全
李少兄2 小时前
MySQL 中为时间字段设置默认当前时间
android·数据库·mysql
码海踏浪2 小时前
从简单到专业在OceanBase中查看SQL是否走索引
数据库·sql·oceanbase
qinyia2 小时前
**使用AI助手在智慧运维中快速定位并修复服务异常:以Nginx配置错误导致502错误为例**
linux·运维·服务器·数据库·mysql·nginx·自动化