割と色々なプログラムで見る機能の1つに、iniファイルの読み込みがあると思います。
読み込むだけなら良いですが、フォーマットエラーを実装するのは面倒です
どうしましょうかね。。
【サンプル】
#include <iostream> #include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ini_parser.hpp> #include <boost/optional.hpp> using namespace std; using namespace boost::property_tree; int main(int argc, char *argv[]) { ptree pt; try{ //ファイルから読み込みツリー構造に値を設定する read_ini("data.ini", pt); //様々な方法で値を取得してみる------------------ //キーが見つからない時に例外を発生させたい場合 cout << pt.get<string>("Data.str") << endl; cout << pt.get<float>("Data.value") << endl; //キーが見つからない時、デフォルト値を取得したい場合 cout << pt.get("Data.int", -1.f) << endl; //キー名にピリオドがある場合などは以下のように指定 cout << pt.get(ptree::path_type("Data/db.conn", '/'), "default") << endl; //optionalクラスを使用する場合 if(boost::optionalvalue = pt.get_optional ("Data.value")) { cout << "value : " << value.get() << std::endl; }else{ std::cout << "value is nothing" << std::endl; } //iteratorで指定セクション配下の値を全て取得 //(get_childの第2引数は、キーが見つからないときの返却値。) const ptree& settings = pt.get_child("UrlList", ptree()); for(ptree::const_iterator i=settings.begin(); i!=settings.end(); ++i){ cout << "itrerator:" << i->first << "=" << i->second.get_value<string>() << endl; } }catch(ptree_error& e){ cout << "ptree_error##" << e.what() << endl; } return 0; } // //
【設定ファイル(data.ini)】
[Data] #ここにコメントも書ける
value = 3
str = Hello
;セミコロンもコメントに使用できる
#ピリオドのあるキー名
db.conn=someone@cd
[UrlList]
url.1 = /a.html
url.2 = /b.html
url.3 = /c.html
url.4 = /d.html
【出力結果】
Hello
3
-1
someone@cd
value : 3
itrerator:url.1=/a.html
itrerator:url.2=/b.html
itrerator:url.3=/c.html
itrerator:url.4=/d.html
【説明】
boostのproperty_treeを使うとなんと1ステップで読み込みできます
read_ini("data.ini", pt); これだけ
この関数の機能は、iniファイルからptreeという階層構造のクラスに値を設定するだけです。
ですので、あとはptreeからの値の取得の仕方さえ知っていれば、簡単に値が取得できます。
まずは、ptreeについてちょっと見てみましょうか。
【ptreeとは】
階層を持った構造の保管庫です。
Windowsのフォルダのように、入れ子でオブジェクトを保管できます。
ptreeには、キー名と値を保管しています。
デフォルトでは両方ともstring型ですが、変更することもできます。
さらに、ptreeはiteratorも使用できます。
イテレータの型としては、C++標準のmapのように、std::pair<string, ptree> を扱います。
ただし、1つ下の階層の値しか取得して回れません。
ptreeのiteratorでは、すべての値を取得できないことに注意です
以下では、実際のコードの説明を見てみましょう!
<値の取り方>
pt.get<string>
get<型>(パス)という形式で値を取得できます。型変換も自動でやってくれて便利です。
C++ で標準で用意されている型くらいは自動で変換できると思います。
パスの指定の仕方は、「セクション名.キー名」です。ピリオド区切りになります。
セクション名とは、[Data]のように角かっこで記述する部分のことです。
<指定したキーが存在しない場合>
キーが存在しない場合は例外が発生します
必ずtry~catchでトラップしましょう。
例外を発生したくない場合、見つからなかったときのデフォルト値を指定できます。
上のサンプルで記述していますので見てみて下さい。
<キー名にピリオドがあるとき>
pt.get(ptree::path_type("Data/db.conn", '/'), "default")
パスの区切りをピリオド以外にしたい場合、path_typeで上記のように指定できます。
簡単ですね
<フォーマット>
まず、コメントですが、「#」「;」の二つが使えます。セクションの後ろにも使用できます。
値の後ろにはコメントを記述できません。
キー名だけの行(=がなく、コメントでもない行)はエラーとなります。
<その他>
キー名で値を取得するだけでなく、iteratorであるセクションの値を全て取得することもできます!
また、設定ファイルの形式は、JSON、XMLなど他の形式も指定できます。
さらに、設定ファイルに書き込みもできます。
かなり便利だと思いません?
【注意点】
とっても便利な機能です。でもいくつか注意点もありますので気をつけましょう。
・boost1.46.0のように古いバージョンですと、コメントはセミコロンしか使えません。
上記で試したバージョンは、1.55で、#をコメントに使用できます
・iniファイルの場合、キー名を重複して記述できません。例外が発生します。
JSONやXMLでは重複を許しているようです。
・JSON、XML形式の設定ファイルも使用できますが、property_treeがJSONやXMLのパーサとして
使用できるというものではないようです。他の方がWEBで書かれた記事の受け売りです。。
・文字コードを指定したい場合、read_ini 関数の第3引数に、std::localeを指定するようですが、
試していないのでちょっと分かりません。すみません
参考: