INIファイルの入出力(Inifile)


■ 概略説明
マイクロソフトがレジストリの使用を推奨する今、あえてINIファイルの使用法をまとめてみました。
INIファイルとはWindows95及び、NT3.xで使用されていた現在のレジストリの原形で、OSの必要なデータはシステムディレクトリのWin.iniファイルに格納されます。今回は、システムデータでなく作成したアプリケーションのローカル情報に限ったデータの格納についての話です。
INIファイルを使用しなくても、データは全てレジストリに格納することは可能ですが、私個人の意見としてはレジストリにも幾つか不満があります。欠点としては
・インストールしたアプリケーションをアンインストールした場合、レジストリデータが部分的に残ってしまう場合がある
・場合によっては、ケース分けしてデータを格納したい場合があるが、レジストリは基本的にユーザー毎に1つの割り当てである
また、INIファイルの長所としては、
・INIファイルでなくユニークなデータファイルでも同様のことができるが、INIファイルの場合仕様が明確なためファイル構造を考える必要が無くユーザーが直接ファイルを編集する場合なども割と分かりやすい。(とは言い切れないが)
私自身も、割とINIファイルを作成する機会が多いので、今回クラス形式でまとめてみました。
まず、サンプルプログラムの画面を見てください。


画面の最上部は、INIファイルのパス名です。このサンプルの場合は、このアプリケーションの作業ディレクトリにある"sample.ini"という名前になります。
セクション名は、レジストリと同じで、各データのグループ毎に付けるグループ名のようなものです。複数指定可能ですが、本サンプルでは、[Test Data Section]1つだけです。
最後にデータですが、データは通常のタイプごとに分けると、文字列タイプ、整数値タイプ、実数値タイプが最もよく使われるので今回のサンプルではこの3種類をサポートしています。これらの3つのデータがセクションの下に置かれます。それぞれの値は左に示されるキー名を持っています。
セクション名は、'\'記号で段階構造にできますが、今回のサンプルでは[セクション名] + [キー名]のシンプルな構造です。
■ プログラムの説明
まず、サンプルプログラムの動作ですが、段階別に説明します。
@ 初めての起動時
このサンプルでは、初期INIファイルは持っていません。
アプリケーションを起動じに、上画面内に表示されるデータは、各データのデフォルト値です。INIファイルのデータには、レジストリ同様デフォルト値が必要です。しかし、初めての起動時にもINIファイルの読込みは行われています。読込み関数は、INIファイルが無くてもエラーは返さず、設定されたデフォルト値を返します。
A 書込み終了
ここで、INIファイルを書き込みます。初めての終了時にはINIファイルが存在しませんが、この場合自動的に指定されたINIファイルが作成されます。
作成された INIファイルの内容は以下のようになります。

B 2回目以降の起動時
2回目以降の起動時は、存在するINIファイルを読み込みます。

このプログラムは、通常のダイアログベースのアプリケーションで、主な処理はCInifileDlg内で行われます。
各データタイプの入出力は、WIN32API関数を使用していますが、このサンプルでのそれぞれの関係は下表のようになります。
データタイプと処理
API関数の有無
サンプルで使用している関数 CIniFileCtrl内の関数名
文字列データの読込み
GetPrivateProfileString ReadString
整数値データの読込み
GetPrivateProfileInt ReadInt
実数値データの読込み
×
GetPrivateProfileString ReadDouble
文字列データの書込み
WritePrivateProfileString WriteString
整数値データの書込み
×
WritePrivateProfileString WriteInt
実数値データの書込み
×
WritePrivateProfileString WriteDouble

お分かりのように、API関数は基本的に文字列データだけを扱い、整数の読込みだけが関数を持ちます。CIniFileCtrlでは、使いやすいように種類毎に関数を分けました。
具体的な使い方ですが、まず INIファイル名、セクション名、キー名、各データのデフォルト値を決めてください。サンプルだと以下のようになります。
/////////////////////////////////////////////////////////////////////////////
//              テスト用INIファイルの各項目名
/////////////////////////////////////////////////////////////////////////////
#define         INI_FILE_NAME   "sample.ini"                    // INIファイル名
                                                                // ディレクトリはこの実行ファイルと同じ
#define         SECT_NAME                       "Test Data Section"     // セクション名
#define         KEY_STR                 "String data key"               // 文字列データのキー名
#define         KEY_INT                 "Integer data key"              // 整数データのキー名
#define         KEY_DBL                 "double data key"               // 実数データのキー名
/////////////////////////////////////////////////////////////////////////////
//              テスト用INIファイルの各項目のデフォルト値(初期値)
/////////////////////////////////////////////////////////////////////////////
#define         DEF_STR_DATA            "abcdef"                        // 文字列データの初期値
#define         DEF_INT_DATA            1234                    // 整数値データの初期値
#define         DEF_DBL_DATA            546.789                 // 実数値データの初期値
/////////////////////////////////////////////////////////////////////////////
次に、CIniFileCtrlを定義しますが、本サンプルではメンバ変数として割り当ててあります。
        CIniFileCtrl                    m_inifile;
INIファイルの読込みは、以下のようになります。読込む前に INIファイルのフルパス名を設定します。
        /////////////////////////////////////////////////////////////////////////
        // INIファイルコントロールのパス名設定.
        m_inifile.SetIniFilePath( m_IniFilePath);
        /////////////////////////////////////////////////////////////////////////
        // INIファイルの読込み.
        m_StrData = m_inifile.ReadString( m_Section, m_StrKey, DEF_STR_DATA);
        m_IntData = m_inifile.ReadInt( m_Section, m_IntKey, DEF_INT_DATA);
        m_DblData = m_inifile.ReadDouble( m_Section, m_DblKey, DEF_DBL_DATA);
前述しましたが、読込み関数は基本的にエラーがありません。INIファイルが見つからなかったとき、或いは該当するセクションやキーが無かった場合は、設定したデフォルト値が返されます。書込み関数も同様に実際は殆どエラーが考えられないのでこのサンプルではエラー時はアサーションにしてあります。
使用の際は、必要に応じてエラー処理を追加してください。
        //      INIファイルの更新.
        //      通常エラーが起こらないので、エラーの場合はプログラムを異常終了します。
        ASSERT( m_inifile.WriteString( m_Section, m_StrKey, m_StrData));
        ASSERT( m_inifile.WriteInt( m_Section, m_IntKey, m_IntData));
        ASSERT( m_inifile.WriteDouble( m_Section, m_DblKey, m_DblData));

CIniFileCtrlクラスだけを、貴方のプロジェクトに組み込む場合は、InifFileCtrl.cpp と IniFileCtrl.hを貴方のプロジェクトにコピーして、[プロジェクトへ追加]でこの2つのファイルを追加してください。
■ ファイルのダウンロード
(MFC6.0プロジェクトファィル16KB)