【问题标题】:How to modify a value with yaml-cpp?如何使用 yaml-cpp 修改值?
【发布时间】:2021-06-01 16:52:49
【问题描述】:

我正在尝试为我的应用程序制作配置文件,为此我使用yaml-cpp 库来生成配置并在用户更改应用程序中的某些设置或某些内容时进行修改。我为此设置了一个单独的类,构造函数生成yaml 文件,如下所示,

Serializer::Serializer(const std::string& filepath)
{
    std::ifstream ifin(filepath);

    if (!ifin)
    {
        emitter << YAML::Comment("Hello");
        emitter << YAML::BeginDoc;
        emitter << "This is the configuration file for the Sample Browser,"
                << YAML::Newline;
        emitter << "feel free to edit this file as needed";
        emitter << YAML::EndDoc;

        emitter << YAML::BeginMap;

        emitter << YAML::Newline << YAML::Key << "Window";
        emitter << YAML::BeginMap;
        emitter << YAML::Key << "SizeW" << YAML::Value << "1280";
        emitter << YAML::Key << "SizeH" << YAML::Value << "720";
        emitter << YAML::EndMap << YAML::Newline;

        emitter << YAML::Newline << YAML::Key << "Media";
        emitter << YAML::BeginMap;
        emitter << YAML::Key << "Autoplay" << YAML::Value << "false";
        emitter << YAML::Key << "Loop" << YAML::Value << "false";
        emitter << YAML::Key << "Muted" << YAML::Value << "false";
        emitter << YAML::EndMap << YAML::Newline;

        emitter << YAML::Newline << YAML::Key << "Display";
        emitter << YAML::BeginMap;
        emitter << YAML::Key << "Font";
        emitter << YAML::BeginMap;
        emitter << YAML::Key << "Family" << YAML::Value << "Sans";
        emitter << YAML::Key << "Size" << YAML::Value << "10";
        emitter << YAML::EndMap;
        emitter << YAML::EndMap << YAML::Newline;

        emitter << YAML::Newline << YAML::Key << "Import_dir";
        emitter << YAML::BeginMap;
        emitter << YAML::Key << "AutoImport" << YAML::Value << "false";
        emitter << YAML::Key << "Directory" << YAML::Value << "/home/apoorv";
        emitter << YAML::EndMap << YAML::Newline;

        emitter << YAML::EndMap;

        std::ofstream ofout(filepath);
        ofout << emitter.c_str();
    }
    else
    {
        wxLogDebug("Config file already exists! Skipping..");
    }
}

这个文件的输出看起来像,

# Hello
---
This is the configuration file for the Sample Browser,
feel free to edit this file as needed
...

Window:
  SizeW: 1280
  SizeH: 720

Media:
  Autoplay: false
  Loop: false
  Muted: false

Display:
  Font:
    Family: "Sans"
    Size: "10"

Import_dir:
  AutoImport: false
  Directory: "/home/apoorv/"

我希望当用户更改字体时,相关键值也会随着所选选项而更改。我尝试制作一个应该这样做的函数,

void Serializer::SerializeDisplaySettings(const std::string& filepath, wxFont& font)
{
    YAML::Emitter out;

    std::string fontFace = font.GetFaceName().ToStdString();
    int fontSize = font.GetPointSize();

    std::ifstream ifin(filepath);

    try
    {
        YAML::Node config = YAML::LoadAllFromFile(filepath)[1];

        auto display = config["Display"];

        if (auto fontSetting = display["Font"])
        {
            wxLogDebug("Changing font settings");
            wxLogDebug("Font face: %s", fontFace);
            wxLogDebug("Font size: %d", fontSize);

            out << YAML::Key << fontSetting["Family"] << YAML::Value << fontFace;
            out << YAML::Key << fontSetting["Size"] << YAML::Value << fontSize;

            std::ofstream ofout(filepath);
            ofout << out.c_str();
        }
        else
        {
            wxLogDebug("Error! Cannot fetch values.");
        }
    }

    catch(const YAML::ParserException& ex)
    {
        std::cout << ex.what() << std::endl;
    }
}

但这会删除整体并仅填充字体名称和大小。如何在不更改/删除整个文件的情况下修改这些值?

【问题讨论】:

    标签: c++ yaml yaml-cpp


    【解决方案1】:

    你覆盖了文件,当然它只包含你给发射器out的项目。如果你想修改加载的文件,你应该更新config中的值并将其全部写回:

    fontSetting["Family"] = fontFace;
    fontSetting["Size"] = fontSize;
    out << config;
    std::ofstream ofout(filepath);
    ofout << out.c_str();
    

    要同时获取其他内容,请在加载时执行此操作:

    auto docs = YAML::LoadAllFromFile(filepath);
    out << YAML::Comment("Hello") << YAML::BeginDoc << docs[0] << YAML::EndDoc;
    YAMl::Node config = docs[1];
    

    【讨论】:

    • 感谢这项工作,但它也删除了我的 cmets 和 YAML Doc。
    • @apoorv569 添加代码以保留其他文档。
    • 感谢您提供的代码。它解决了这个问题,但它也弄乱了我的间距和新行,在原始帖子中,您会看到所有父节点之后都有新行,即在 WindowMediaDisplayImport_Dir 之前。我是否必须手动编辑文件,因为它会在编辑时再次添加这些新行。因为当我向文件中添加更多项目时,每次编辑文件时重新添加这些 cmets 和所有项目都会变得非常乏味。
    • @apoorv569 在加载和修改 YAML 文件时,您无法保留所有格式,详情请参阅 this question。这不是 YAML 的工作方式。正如您在EventHandler 中看到的那样,解析器不为 cmets、非内容换行符等提供事件,因此它们将不可恢复地丢失。
    • @apoorv569 XML 被指定为在加载时保留所有内容,如果这是您所追求的。当然,许多开发人员偏爱 JSON/YAML/TOML 等是有原因的。这些语言是为用户友好而编写的,其中包括使用空格来进行解析器忽略的格式设置,这是您不能这样做的主要原因准确复制加载的文件。
    猜你喜欢
    • 1970-01-01
    • 2015-12-06
    • 2022-01-01
    • 2012-11-27
    • 1970-01-01
    • 2018-10-04
    • 2021-02-28
    • 2019-06-23
    • 1970-01-01
    相关资源
    最近更新 更多