在程序員的開發生涯中,讀寫配置文件必不可少。
配置文件有利于我們靈活配置工程,解決大量重復勞動,也方便調試。
配置文件的格式有很多,最簡單的有一行一行的文本,也有像 json、xml、protocol buffer 這樣結構化的格式,當然也有 yaml 這種格式。
今天的博文介紹的是如何在 C++ 開發中利用 yaml-cpp 開源庫讀寫 yaml 配置文件。
如果有 Python 開發經驗的同學,可能知道用 Python 讀取 yaml 是再簡單不過了,但是 C++ 麻煩一點,它需要你自己下載源碼然后編譯生成庫文件。
官方的使用教程在這里
https://github.com/jbeder/yaml-cpp/wiki/Tutorial
1.yaml-cpp
yaml-cpp 是一個開源庫,地址在 github 上,https://github.com/jbeder/yaml-cpp
yaml-cpp 是通過 CMake 來進行構建和編譯的。
在這里假設讀者都有 CMake 相關的經驗,沒有的同學自行百度。我的博文也寫過比較簡單的幾篇,有興趣的可以去看一看。
如果沒有,可以用這段一鍵腳本源碼編譯
#!/bin/bash
yum remove cmake -y && rm -f /usr/bin/cmake
wget -c https://github.com/Kitware/CMake/releases/download/v3.14.2/cmake-3.14.2.tar.gz
tar xvf cmake-3.14.2.tar.gz
cd $(pwd)/cmake-3.14.2
./bootstrap
gmake
gmake install
ln -s /usr/local/bin/cmake /usr/bin/
cmake --version
首先下載源碼。
https://github.com/jbeder/yaml-cpp
然后,在源碼目錄創建一個 build 文件夾。
mkdir build
進入到 build 文件夾,然后執行 cmake 命令。
cd build
cmake ..
make
注意的是 cmake 后面是 ..,這代表從 build 上一層目錄查找 CMakeLists.txt ,然后編譯的文件都會存放在 build 文件夾,如果對編譯的效果不滿意,只要刪除 build 文件就好了,其他源碼目錄并不受影響,這是 cmake 編譯時的基本套路。
yaml-cpp 默認構建的就是靜態庫,也就是 unix 類系統下的 .a 文件,如果你想構建動態庫的話,就需要在 cmake 時指定。
cmake .. -D BUILD_SHARED_LIBS=ON //不建議,動態庫需要每個部署環境都安裝
編譯成功后,會生成庫文件,你只需要將庫文件和頭文件拷貝到你自己的工程當中,就可以使用了。
可以看到cmake后make生成了靜態庫文件
編譯完成后測試一下
make test
完全ok
2.需要處理好頭文件。
你如果不想每次都到 copy 頭文件到不同的工程中,那么你可以將頭文件 copy 到系統默認的頭文件目錄,比如 ubuntu 的地址是 /usr/local/include,將庫文件拷貝到系統默認的 lib 文件就好了,比如 ubuntu 是 /usr/local/lib。
其實不用copy到lib,make install會自動把編譯出來的頭文件保存到/usr/local/lib
make install
我建議每次直接拷貝.a文件到工程項目里。有了頭文件和庫,我們就可以順利寫代碼了。
拷貝include目錄,和build目錄下的libyaml.a文件
新建一個文件夾也叫yaml-cpp,把include拷進來,再在里面新建一個lib文件夾,把libyaml.a拷貝進去
形成如下結構的文件夾,以后新建項目我們就把它拷貝到第三方靜態庫文件夾里
這里我們寫一個簡單的讀取yaml的cpp程序,把我們的靜態庫目錄拷貝進
thirdlib
文件夾下項目結構如下
config.yaml
custom_db:
db_domain: 10.0.0.8
db_username: root
db_passwd: my_passwd
db_schema: test
redis:
redis_domain: 10.0.0.10
redis_passwd: 123456
hello:
num_config: [1141studio]
name_config: [powered, by, 1141studio]
hello.cpp
#include <iostream>
#include <string>
#include <stdio.h>
#include <unistd.h>
#include "yaml-cpp/yaml.h"
#include <vector>
const std::string DB_CONF = "config.yaml";
int main(int argc, char * argv[]) {
/*----------------------------------- test yaml ----------------------------------------*/
printf("hello world\n");
std::cout << "this code is only for test yaml" << std::endl;
/* Node conf. */
YAML::Node conf = YAML::LoadFile(DB_CONF);
/*----------------------------------- display db_config ----------------------------------------*/
std::cout << "Database:"<< std::endl;
std::cout << "domain: " << conf["custom_db"]["db_domain"].as<std::string>() << std::endl;
std::cout << "username:" << conf["custom_db"]["db_username"].as<std::string>() << std::endl;
std::cout << "passwd: " << conf["custom_db"]["db_passwd"].as<std::string>() << std::endl;
std::cout << "schema: " << conf["custom_db"]["db_schema"].as<std::string>() << std::endl;
/*----------------------------------- display redis ----------------------------------------*/
std::cout << "Redis" << std::endl;
std::cout << "redis_domain: " << conf["redis"]["redis_domain"].as<std::string>() << std::endl;
std::cout << "redis_passwd: " << conf["redis"]["redis_passwd"].as<std::string>() << std::endl;
/*----------------------------------- display hello ----------------------------------------*/
std::cout << "HelloServer" << std::endl;
/* vector of name string. */
std::vector<std::string> name_vec = conf["hello"]["num_config"].as<std::vector<std::string> >();
if(!name_vec.empty())
std::cout << name_vec[0] << std::endl;
return 0;
}
編譯
g++ -std=c++11 -I./thirdlib/yaml-cpp/include test_db.cpp -L./thirdlib/yaml-cpp/lib -lyaml-cpp -o HelloServer
其中 -Idir
讓編譯器在dir目錄搜索頭文件include
-Ldir
讓編譯器在dir目錄搜索靜態庫
-lname
讓編譯器鏈接libname.a
的目錄
可以看到成功的讀取了yaml文件,以后的配置文件就不用寫死在代碼里了
更多api可以參考https://cloud.tencent.com/developer/article/1423468
https://www.cnblogs.com/huodaozhe/p/12026327.html
還有類似的json庫jsoncpp:https://blog.csdn.net/guotianqing/article/details/94378309
googletest:https://blog.csdn.net/guotianqing/article/details/104055221
mysql: https://blog.csdn.net/LV_YONG/article/details/80584415