INIファイルを読み書きするには?.NET TIPS

» 2003年06月20日 05時00分 公開
[川俣晶(http://www.autumn.org/)株式会社ピーデー(http://www.piedey.co.jp/)]

この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。

「.NET TIPS」のインデックス

連載目次

 INIファイルは、16bit CPUに対応したWindows 3.1以前のWindowsで使用されていた各種設定の保存用ファイルである。拡張子が「.ini」であることから、INIファイル(イニ・ファイル)と呼ばれる。これは、単純なテキスト・ファイルに格納されることから、扱いやすく、さまざまな用途に使用された。しかし、単純な構造しか持てず、また大量のデータ書き込みなどを行うと遅いことから、32bit時代のWindowsではレジストリにその役割を取って代わられた。現在では、レジストリも過去のものになりつつあり、アプリケーションに関する情報はXMLファイルとして保存することが推奨されている。

 このようにすでに2世代も古い技術ではあるが、過去の資産の継承という意味で、INIファイルを扱うことが求められる場合がある。しかし、.NET FrameworkにはINIファイルを扱う機能は含まれていない。そのため、これを扱う機能を別途用意する必要が生じる。

 INIファイル自身は単純な構造であるため、テキスト・ファイルとして開いて処理することも不可能ではない。しかし、INIファイルの種類によっては、レジストリにマップされたり、OSがキャッシュしていたりする場合もあるので、システムが提供しているWin32 APIを呼び出す方法を使うのがより確実だろう。

 なお、本稿では、INIファイルを扱うWin32 APIに関する基本的な知識を持っていることを前提として説明を行っている。

DLL呼び出しを宣言する

 このTIPSのために、Win32 API呼び出しを行う宣言を作成した。これを用いれば、.NETのアプリケーションからWin32 API呼び出しを簡単に行うことができる。ただし、1つだけ問題に遭遇した。StringBuilderクラス(System.Text名前空間)を利用して文字列を受け取る通常のWin32 API呼び出し手法では、INIファイル中の指定セクションのキー一覧を得る機能と、指定ファイルのセクション一覧を得る機能が実現できなかったのである(文字列を受け取るWin32 API呼び出しについては「TIPS:Win32 APIやDLL関数に文字列や文字列バッファを渡すには?」で解説している)。通常は、Win32 APIにあるGetPrivateProfileString関数を用いて結果の文字列を受け取るが、この2つの機能を使用する場合に限り、返される文字列が複数の文字列から構成される特殊な構造になってしまう。それが、.NET側の型とうまくマーシャリングができなかったのである。これを回避するために、byte配列を使って受け取り、byte配列を明示的に文字列に変換するという回りくどいコーディングが必要とされた。もし、繰り返し使う場合は、この手順もライブラリ化してしまうとよいだろう。

 さて、Win32 API呼び出しを行うための宣言は、以下に示したサンプル・プログラム中のIniFileHandlerクラスに当たる。これはそのままコピーして利用することができる。Win32 APIの宣言さえすれば、あとは通常のメソッド呼び出しと同じようにWin32 APIを呼び出して利用することができる。それぞれの機能がどのようなコードで実現されているかはサンプル・プログラムのコメントで場所を示した。

// inifile.cs

using System;
using System.IO;
using System.Text;
using System.Runtime.InteropServices;

class IniFileHandler {
  [DllImport("KERNEL32.DLL")]
  public static extern uint
    GetPrivateProfileString(string lpAppName,
    string lpKeyName, string lpDefault,
    StringBuilder lpReturnedString, uint nSize,
    string lpFileName);

  [DllImport("KERNEL32.DLL",
      EntryPoint="GetPrivateProfileStringA")]
  public static extern uint
    GetPrivateProfileStringByByteArray(string lpAppName,
    string lpKeyName, string lpDefault,
    byte [] lpReturnedString, uint nSize,
    string lpFileName);

  [DllImport("KERNEL32.DLL")]
  public static extern uint
    GetPrivateProfileInt( string lpAppName,
    string lpKeyName, int nDefault, string lpFileName );

  [DllImport("KERNEL32.DLL")]
  public static extern uint WritePrivateProfileString(
    string lpAppName,
    string lpKeyName,
    string lpString,
    string lpFileName);
}

public class Sample {
  static void Main() {

    // キーと値を書き加える
    IniFileHandler.WritePrivateProfileString(
        "アプリ1", "キー1", "ハロー", @"c:\sample.ini");
    IniFileHandler.WritePrivateProfileString(
        "アプリ1", "キー2", "1234", @"c:\sample.ini");
    IniFileHandler.WritePrivateProfileString(
        "アプリ2", "キー1", "good morning", @"c:\sample.ini");

    // 文字列を読み出す
    StringBuilder sb = new StringBuilder(1024);
   
    IniFileHandler.GetPrivateProfileString("アプリ1", "キー1",
            "default", sb, (uint)sb.Capacity, @"c:\sample.ini");

    Console.WriteLine(
            "アプリ1セクションに含まれるキー1の値: {0}",
            sb.ToString());

    // 整数値を読み出す
    uint resultValue
            = IniFileHandler.GetPrivateProfileInt(
                "アプリ1", "キー2", 0, @"c:\sample.ini");
    Console.WriteLine(
            "アプリ1セクションに含まれるキー2の値: {0}",
            resultValue);

    // 指定セクションのキーの一覧を得る
    byte [] ar1 = new byte[1024];
    uint resultSize1
          = IniFileHandler.GetPrivateProfileStringByByteArray(
                "アプリ1", null, "default", ar1,
                (uint)ar1.Length, @"c:\sample.ini");
    string result1 = Encoding.Default.GetString(
                            ar1, 0, (int)resultSize1-1);
    string [] keys = result1.Split('\0');
    foreach (string key in keys) {
      Console.WriteLine(
        "アプリ1セクションに含まれるキー名: {0}", key);
    }

    // 指定ファイルのセクションの一覧を得る
    byte [] ar2 = new byte[1024];
    uint resultSize2
          = IniFileHandler.GetPrivateProfileStringByByteArray(
                null, null, "default", ar2,
                (uint)ar2.Length, @"c:\sample.ini");
    string result2 = Encoding.Default.GetString(
                            ar2, 0, (int)resultSize2-1);
    string [] sections = result2.Split('\0');
    foreach (string section in sections) {
      Console.WriteLine(
          "このファイルに含まれるセクション名: {0}", section);
    }

    // 1つのキーと値のペアを削除する
    IniFileHandler.WritePrivateProfileString(
        "アプリ2", "キー1", null, @"c:\sample.ini");

    // 指定セクション内の全てのキーと値のペアを削除する
    IniFileHandler.WritePrivateProfileString(
        "アプリ1", null, null, @"c:\sample.ini");
  }
}

// コンパイル方法:csc inifile.cs

INIファイルを読み書きするC#のサンプル・プログラム(inifile.cs)
inifile.csのダウンロード

Visual Basic .NET版:inifile.vbのダウンロード


 ここではINIファイルに対するそれぞれの基本操作について、順に解説していこう。上記のサンプル・プログラムの該当個所と照らし合わせながら読み進めていただきたい。

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。