iniファイルを読み込むには?

テーマ:

割と色々なプログラムで見る機能の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::optional value = 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>("Data.str")


  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を指定するようですが、

  試していないのでちょっと分かりません。すみません ショック!



参考:

boostとは?

違う型どうしを自由に変換するには?
Boost本家のPropertyTreeリファレンス