007-nlohmann/json 项目应用-C++开源库108杰

news2025/6/7 9:21:38

本课为 fswatch(第一“杰”)的示例项目加上对配置文件读取的支持,同时借助 第三“杰” CLI11 的支持,完美实现命令行参数与配置文件的逻辑统一。 

012-nlohmann/json-4-项目应用

项目基于原有的 CMake 项目 HelloFSWatch 修改。

  • CMakeLists.txt :该文件基于原项目,没有任何改动。

  • .vscode/setting.json ,改动如下:

{   
    "cmake.debugConfig": {
        "cwd": "${workspaceFolder}",
        "args": ["-m", "3", "--log-level", "info"],
        "externalConsole": false
    }
}

重点:

①  args字段:添加命令行参数;

② cwd 字段:设置程序在项目根目录下运行(而在程序所在的 build 子目录内)。

  • myConfig.json 测试用的配置文件
{
    "paths": [ "c:\\tmp", "c:/tmp/aaa" , "d:/tmp" ],
    
    "maxOutput": -1,      
    "createdOnly" : false,
    
    "destination": "d:\\我的学习资料",
    
    "toBase64": [".png", ".jpg", ".jpeg"],
    "toSnappy": [".txt", ".pdf"],

    "logFile": ".\\log\\log.txt",
    "logLevel": "off"
 }
  • main.cpp
#include <ctime>

#include <iostream>
#include <iomanip>
#include <memory> // 智能指针 shared_ptr<>

#include <libfswatch/c++/monitor_factory.hpp>
#include <CLI/CLI.hpp> 

#include <nlohmann/json.hpp>

#include "myiconv.hpp"

using json = nlohmann::json;

namespace Watch::settings
{
//----------------------------------------------    

// 日志级别(暂使用手工定义,007杰讲改用三方库中的定义)
enum class LogLevel 
{
    // 跟踪、调试、信息、警告、错误 、危急、关闭
    trace, debug, info, warn, err, critical, off
};

// 让枚举 LogLevel 支持与JSON双向转换
NLOHMANN_JSON_SERIALIZE_ENUM(LogLevel,
{
    {LogLevel::trace, "trace"},
    {LogLevel::debug, "debug"},
    {LogLevel::info, "info"},
    {LogLevel::warn, "warn"},
    {LogLevel::err, "err"},
    {LogLevel::critical, "critical"},
    {LogLevel::off, "off"}
})

// 配置数据的结构体
struct Config
{
    std::vector<std::string> paths;
    int maxOutput = -1;
    bool createdOnly = false;

    std::string destination; 
    std::vector<std::string> toBase64;
    std::vector<std::string> toSnappy;
    std::string logFile = "./log.txt";
    LogLevel logLevel = LogLevel::off;     
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Config,     
    paths, maxOutput, createdOnly, 
    destination, toBase64, toSnappy, 
    logFile, logLevel)

std::string getLogLevelName(LogLevel ll)
{
    json j = ll;
    return j.get<std::string>();
}

std::map<std::string, LogLevel> logLevelNameMap
{
    {getLogLevelName(LogLevel::trace), LogLevel::trace},

    #define llNameItem(ll) {getLogLevelName(LogLevel::ll), LogLevel::ll}

    llNameItem(debug),
    llNameItem(info),
    llNameItem(warn),
    llNameItem(err),
    llNameItem(critical),
    llNameItem(off)

    #undef llNameItem
};

// 配置数据“格式器”
class MyCLIConfigAdaptor : public CLI::Config
{
public:
    // 如何从 JSON 数据读出 各个配置项
    std::vector<CLI::ConfigItem> from_config (std::istream &input) const override;

    // 如何从app,生成配置文件内容(字符串)
    std::string to_config (CLI::App const* app, 
        bool default_also, bool write_description, std::string prefix) const override
    { return ""; }
};

std::vector<CLI::ConfigItem> MyCLIConfigAdaptor::from_config (std::istream &input) const 
{
    try
    {
        json j = json::parse(input, nullptr, true /*允许异常*/, true /*允许注释*/);

        auto cfg = j.get<settings::Config>();

        auto items = std::vector<CLI::ConfigItem>
        {
            {{}, "paths", cfg.paths },
            {{}, "max-ouput", { std::to_string(cfg.maxOutput) }}, // 视频中误为 "max-count"
            {{}, "created-only", { cfg.createdOnly? "true" : "false"} },
            {{}, "destination", { cfg.destination }},
            {{}, "to-base64", cfg.toBase64},
            {{}, "to-snappy", cfg.toSnappy},
            {{}, "log-file", {cfg.logFile}},
            {{}, "log-level", {std::to_string(static_cast<int>(cfg.logLevel))}}
        };

        return items;
    }
    catch(json::exception const& e)
    {
        std::cerr << "JSON 配置数据有误。" << e.what() << std::endl;
    }
    catch(std::exception const& e)
    {
        std::cerr << "读取并转换配置数据发生异常。" << e.what() << std::endl;
    }

    return {};
}

//----------------------------------------------    
} // namespace Watch::settings

Watch::settings::Config theConfig; // 全局唯一的配置

// 返回值:必须是 void,入参必须是 std::vector<fsw::event> const & 和 void *
void on_file_changed(std::vector<fsw::event> const & events, void *)
{
    /* 略,保持原有实现不变;本课,配置数据尚未发挥作用 */    
}

int main(int argc, char** argv) // 主函数
{
    // 一、定义一个CLI::App 的变量
    CLI::App app("HelloFSWatch");

    // 1.1 指定(默认的)配置文件
    app.set_config("--config", "./myConfig.json", "指定配置文件");

    // 1.2 创建并指定定制的配置数据格式解析器
    app.config_formatter(std::make_shared<Watch::settings::MyCLIConfigAdaptor>());

    // 二、添加命令行参数
    try
    {
        app.add_option("paths", theConfig.paths, 
                     "待监控的文件夹路径(可含多个)")->required();
        app.add_option("--max-output,-m", 
               theConfig.maxOutput, "启动后输出事件个数")->default_val(-1);
        app.add_flag("-c,--created-only", theConfig.createdOnly, "只关注新建信息");
        app.add_option("--destination,-d", 
               theConfig.destination, "输出文件路径")->required();
        app.add_option("--to-base64", theConfig.toBase64,
                     "需要转成base64的文件的扩展名(数组)");
        app.add_option("--to-snappy", theConfig.toSnappy, 
                     "需要转成snappy的文件的扩展名(数组)");
        app.add_option("--log-file", 
             theConfig.logFile, "日志文件路径")->default_val("./log.txt"); 
        app.add_option("--log-level", 
             theConfig.logLevel, "可输出的最小日志级别")
               ->default_val(Watch::settings::LogLevel::off)
               ->transform(CLI::CheckedTransformer(Watch::settings::logLevelNameMap));
            
        // 三、开始解析命令行
        app.parse(argc, argv);
    }
    catch(std::exception const& e)
    {
        std::cerr << e.what() << std::endl;
        return -1;
    }

    // 显示当前生效的配置数据
    json j = theConfig;
    std::cout << "\n当前发挥作用的配置是:\n" << j.dump(2) << std::endl;

    auto *monitor = fsw::monitor_factory::create_monitor(
        system_default_monitor_type,
        theConfig.paths,
        on_file_changed
    );

    // 启动监控
    monitor->start();  // 进入死循环
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

移动端测试岗位高频面试题及解析

文章目录 一、基础概念二、自动化测试三、性能测试四、专项测试五、安全与稳定性六、高级场景七、实战难题八、其他面题 一、基础概念 移动端测试与Web测试的核心区别&#xff1f; 解析&#xff1a;网络波动&#xff08;弱网测试&#xff09;、设备碎片化&#xff08;机型适配&…

Git GitHub Gitee

一、Git 是一个免费、开源的分布式版本控制系统。 版本控制&#xff1a;一种记录文件内容变化&#xff0c;以便将来查阅特定版本修订情况的系统。它最重要的就是可以记录文件修改历史记录&#xff0c;从而让用户可以看历史版本&#xff0c;方便版本切换。 1.和集中式版本控制…

PLSQLDeveloper配置OracleInstantClient连接Oracle数据库

PL/SQLDeveloper配置Oracle Instant Client连接Oracle数据库 文章目录 PL/SQLDeveloper配置Oracle Instant Client连接Oracle数据库 1. Oracle Instant Client下载与配置1. Oracle Instant Client下载2. Oracle Instant Client解压配置1. 解压2. 配置 2. PL/SQL Developer下载、…

【Oracle】触发器

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 触发器基础概述1.1 触发器的概念与特点1.2 触发器的分类1.3 触发器的执行顺序 2. DML触发器2.1 基础DML触发器2.1.1 INSERT触发器2.1.2 UPDATE触发器2.1.3 DELETE触发器 2.2 高级DML触发器2.2.1 复合触发器2…

基于深度学习的无人机轨迹预测

完整代码见文末 随着无人机技术的不断发展&#xff0c;无人机在农业、物流、监控等领域的应用日益广泛。精准的轨迹预测不仅能够提高无人机飞行的效率和安全性&#xff0c;还能在应对复杂环境下的突发状况时做出迅速反应。因此&#xff0c;基于深度学习的无人机轨迹预测已成为…

git连接本地仓库以及gitee

参考:gitee创建新仓库并上传代码_gitee新建仓库导入代码-CSDN博客 git初始化以及添加git分支 在idea查看master主分支 报错 原因gitee推送更新失败问题记录&#xff1a;remote: error: hook declined to update refs/heads/master-CSDN博客 取消邮箱暴露

麒麟v10系统的docker重大问题解决-不支持容器名称解析

今天给客户在麒麟v10Kylin-Server-V10-SP1下安装nextcloudonlyoffice的时候出现无法连接onlyoffice的问题,经过分析找到了是docker版本过低的原因,现在把解决思路和步骤分享给大家。 一、问题 用一键安装工具,给客户装好了系统,Nextcloud可以正常访问 但是访问nextcloud中的o…

基于5G下行信号的模糊函数分析matlab仿真,对比速度模糊函数和距离模糊函数

目录 1.引言 2.算法仿真效果演示 3.数据集格式或算法参数简介 4.MATLAB部分程序 5.算法涉及理论知识概要 6.参考文献 7.完整算法代码文件获得 1.引言 模糊函数&#xff08;Ambiguity Function, AF&#xff09;是信号处理领域用于分析信号时频分辨能力的核心工具&#xf…

Redis 过期了解

Redis 版本&#xff1a;5.0 &#xff1a; 一&#xff1a;过期监听&#xff1a; Spring Data Redis 封装了 Redis 的 Pub/Sub 功能&#xff0c;提供了对 key 过期事件的监听支持。 1. 核心类&#xff1a;KeyExpirationEventMessageListener 这个抽象类是 Spring 提供的&#x…

JAVA理论-JAVA基础知识

1.Java 基础 知识 1.1 面向对象的特征&#xff08;了解&#xff09; 面向对象的特征&#xff1a;封装、继承、多态、抽象 封装&#xff1a;就是把对象的属性和行为&#xff08;数据&#xff09;结合为一个独立的整体&#xff0c;并尽量隐藏对象的内部细节&#xff0c;公开我希…

免费无限使用GPT Plus、Claude Pro、Grok Super、Deepseek满血版

渗透智能-ShirtAI&#xff0c;可以免费无限使用GPT Plus、Claude Pro、Grok Super、Deepseek满血版、除此之外还能免费使用AI搜索、Gemini AI、AI照片修复、AI橡皮擦、AI去背景、AI智能抠图、AI证件照、OCR识别、在线思维导图、在线绘图工具、PDF工具箱、PDF翻译。 传送入口&a…

SoloSpeech - 高质量语音处理模型,一键提取指定说话人音频并提升提取音频清晰度和质量 本地一键整合包下载

视频教程&#xff1a; 一个强大的语音分离和降噪软件 SoloSpeech 是由约翰霍普金斯大学、香港中文大学、南洋理工大学、清华大学及布拉格理工大学等多所高校共同主导开源的一个创新的语音处理项目&#xff0c;旨在解决在多人同时说话的环境中&#xff0c;准确提取并清晰呈现特定…

深入解析 Java ClassLoader:揭开 JVM 动态加载的神秘面纱

大家好&#xff0c;这里是架构资源栈&#xff01;点击上方关注&#xff0c;添加“星标”&#xff0c;一起学习大厂前沿架构&#xff01; Java 之所以能实现“一次编写&#xff0c;到处运行”&#xff0c;很大程度得益于其虚拟机&#xff08;JVM&#xff09;强大的跨平台能力。…

CICD实战(一) -----Jenkins的下载与安装

服务器IPJenkins192.168.242.153gitlab192.168.242.154 1、安装工具&#xff08;可选&#xff0c;如果有就不需要安装&#xff09; sudo yum install wget net-tools 2、关闭防火墙 #关闭防火墙(如果是云服务器部署,去安全组放通对应的端口即可) systemctl stop firewalld …

Devops系列---python基础篇二

1、列表 1.1 概念 格式&#xff1a; 名称 [ “元素1”,“元素2”,…] #定义一个列表 computer ["主机","键盘","显示器","鼠标"]类型方法用途查index(“元素”)查看元素索引位置count(“元素”)统计元素出现的次数reverse()倒序排…

​​TLV4062-Q1​​、TLV4082-Q1​​迟滞电压比较器应用笔记

文章目录 主要作用应用场景关键优势典型应用示意图TLV4062-Q1 和 TLV4082-Q1 的主要作用及应用场景如下: 主要作用 精密电压监测:是一款双通道、低功耗比较器,用于监测输入电压是否超过预设阈值。 集成高精度基准电压源(阈值精度1%),内置60mV迟滞功能,可避免因噪声导致的…

DHCP介绍

DHCP介绍 1 DHCP简述2 DHCP协议分析2.1 主要流程2.2 DHCP全部报文介绍2.3 IP租用更新报文2.4 DHCP协议抓包分析 3 DHCP应用3.1 DNSmasq参数配置3.2 DNSmasq框架代码3.2.1 创建socket监听67端口3.2.2 监听67端口3.2.3 处理DHCP请求 3.3 DNSmasq模块排障方法 4 常见问题排查4.1 问…

[蓝桥杯]耐摔指数

耐摔指数 题目描述 X 星球的居民脾气不太好&#xff0c;但好在他们生气的时候唯一的异常举动是&#xff1a;摔手机。 各大厂商也就纷纷推出各种耐摔型手机。X 星球的质监局规定了手机必须经过耐摔测试&#xff0c;并且评定出一个耐摔指数来&#xff0c;之后才允许上市流通。…

2024年第十五届蓝桥杯青少Scratch初级组-国赛—画矩形

2024年第十五届蓝桥杯青少Scratch初级组-国赛—画矩形 题目点下方&#xff0c;支持在线编程&#xff0c;在线获取源码和素材&#xff5e; 画矩形_scratch_少儿编程题库学习中心-嗨信奥 程序演示可点下方&#xff0c;支持源码获取&#xff5e; 画矩形-scratch作品-少儿编程题库…

JMM初学

文章目录 1,线程间的同步和通信1.1, 共享内存并发模型 (Shared Memory Model)线程通信机制线程同步机制特点 1.2, 消息传递并发模型 (Message Passing Model)线程通信机制线程同步机制特点 适用场景对比 2,Java内存模型JMM2.0,Java内存模型的基础&#xff08;1&#xff09;内存…