INIファイルの読み込み・書き込みをまとめて行うことができるライブラリ「inifile-cpp」

# はじめに
c++でINIファイルの読み込み・書き込みを行う際、Win32APIのGetPrivateProfileStringやWritePrivateProfileStringを使用していましたが、ファイルパス指定をすることで一括でINIファイル内の情報の読み込み・書き込みができる便利なライブラリ「**inifile-cpp**」を知ったため、紹介したいと思います。

# inifile-cppとは
GitHub内で公開されている、INIファイルの読み書きを行うことができるライブラリです。

https://github.com/Rookfighter/inifile-cpp

Win32APIと比較した動作の違いを紹介します。

## 読み込み
```:inifile-cpp
std::string Word = "default str";
myIni.load(path);
std::string str = myIni["Section"]["KeyWord1"].as<std::string>();
```
```:Win32API
std::wstring strInfilePath = L"config.ini";
TCHAR waBuf[ MAX_PATH ];
GetPrivateProfileString( L"Section", L"KeyWord1", L"デフォルト文字列", waBuf, _countof( waBuf ), strInfilePath.c_str());
```
Win32APIではキーごとに読み込みが必要になりますが、inifile-cppの**load**関数を使用すると、INIファイル内のキーをまとめて読み込むことができます。

Win32APIでは読み込み失敗時のデフォルト値を任意の値に設定ができますが、inifile-cppの場合は数値の場合は0、文字列の場合は“”(Empty)、bool値はtrueとなります。
任意のデフォルト値を設定したい場合は、事前にデフォルト値を実装しておく必要あります。

## 書き込み
```:inifile-cpp
ini::IniFile myIni;
myIni["Section"]["KeyWord2"] = "wow!";
myIni.save(path);
```
```:Win32API
std::wstring strInfilePath = L"config.ini";
WritePrivateProfileString( L"Section", L"KeyWord2", L"デフォルト文字列", strInfilePath.c_str());
```
読み込みと同様に、Win32APIではキーごとに書き込みが必要になりますが、inifile-cppの**save**関数を使用すると、INIファイル内のキーをまとめて書き込むことができます。

## 変換

### inifile-cpp
#### 読み込み
loadした後に、myIni[セクション][キー].as<型>();を実行することで、読み込んだ値を簡単に任意の型に変換することができます。
#### 書き込み
```
myIni["Section2"]["KeyBool2"] = false;
```
書き込む内容の設定を行うときに、変換が必要な場合はinifile-cppが自動で変換してくれます。
### Win32API
Win32APIでは、以下の表の関数が用意されており、関数の仕様に当てはまらない型の読み書きについては各自で変換を行う必要があります。

#### INIファイルの読み書きを行うWin32API
|動作|関数名|備考|
|-|-|-|
|読み込み|GetPrivateProfileString|文字列を読み込む|
|読み込み|GetPrivateProfileInt|数値を読み込む|
|書き込み|WritePrivateProfileString|数値を書き込みたい場合は文字列に変換しておく必要がある|


# 導入

前項記載のURLからinifile-cppのプロジェクトをクローンし、「include」フォルダに含まれる「inicpp.h」を取得します。
INIファイルの読み書き機能を実装したいプロジェクトにinicpp.hを追加し、ソース内で「inicpp.h」をインクルードします。

# 使用例

**Load**でINIファイルを読み込み(load)・読み込んだ値の検証を行い、
**Save**でINIファイルに書き込む値の設定、INIファイルに書き込み(save)を行っています。
※読み込み、書き込み時に指定したパスが存在しない場合は作成されます。

## 動作確認環境
* Windows11 22h2
* VisualStudio2022(v143)
* ISO C++14 

```:config.ini
[Section1]
KeyInt1=1000

[Section2]
KeyBool1=TRUE

[Section3]
KeyWord1=Good-Bye

※Bool値はダブルコーテーションなしのtrueまたはfalseで記載する(大文字・小文どちらでも可)
```

```config.cpp
#include <inicpp.h>
#include <string>
#include <iostream>

class Config
{
public:

    //キーが読み込めない・存在しなかった時のデフォルト値
    int Num = 500;
    bool Bool = false;
    std::string Word = "Hello";
    ini::IniFile myIni;

    //INIファイルを読み込み・読み込んだ値の検証を行う
    void Load(std::string& path)
    {
        //INIファイルを読み込む
        myIni.load(path);

        //検証
        int temp1 = myIni["Section1"]["KeyInt1"].as<int>();
        if (0 < temp1 && temp1 <= 10000)
        {
            Num = temp1;
        }

        bool temp2 = myIni["Section2"]["KeyBool1"].as<bool>();
        if (temp2 != NULL)
        {
            Bool = temp2;
        }

        std::string temp3 = myIni["Section3"]["KeyWord1"].as<std::string>();
        if (!temp3.empty())
        {
            Word = temp3;
        }
    }

    void Save(std::string& path)
    {
        //INIファイルに書き込む値を設定する
        myIni["Section1"]["KeyInt2"] = 123;
        myIni["Section2"]["KeyBool2"] = false;
        myIni["Section3"]["KeyWord2"] = "wow!";

        //INIファイルに書き込む
        myIni.save(path);
    }
};

Config config;

void main()
{
    std::string inipath = "config.ini";

    printf_s("Load Before．Num = %d, Bool = %s, Word = %s\n", config.Num, config.Bool ? "true" : "false", config.Word);

    //読み込み
    config.Load(inipath);

    printf_s("Load After. Num = %d, Bool = %s, Word = %s\n", config.Num, config.Bool ? "true" : "false", config.Word);

    //書き込み
    config.Save(inipath);

}
```
```:実行結果：コンソール
Load Before．Num = 500, Bool = false, Word = Hello
Load After. Num = 1000, Bool = true, Word = "Good-Bye"
```
```実行結果：config.ini
[Section1]
KeyInt1=1000
KeyInt2=123
[Section2]
KeyBool1=TRUE
KeyBool2=false
[Section3]
KeyWord1=Good-Bye
KeyWord2=wow!
```
読み込み・書き込みができました！

# おわりに
Win32APIを使用してINIファイルの読み込み・書き込みを行う場合はINIファイルのキーごとに関数を呼び出す必要がありますが、inicpp-fileを使用すれば、ファイル内のキーを一括で読み書きできるのがとても便利だと思いました。

WindowsAPIだけでなくGitHubなどで公開されているライブラリも使用し、よりよいコードを書いていきたいです。

# 参考
* https://github.com/Rookfighter/inifile-cpp
* https://www.wabiapp.com/WabiSampleSource/windows/get_private_profile.html
* https://www.wabiapp.com/WabiSampleSource/windows/write_private_profile.html