iniファイルも読みたいっすよ

と、言うわけで前回のXML読み込みに引き続き、XMLの書き込み、 と思ったんですが、やめました。(気まぐれシェフ)

今回は、

XMLって何かやっぱ読みにくいし、設定は普通にiniファイルに書きたいっす。 自分、iniファイルの為ならチャンコも我慢するっす。

と言う方の為に、今まで習得してきた技術を使ってiniファイルを読んでみようかと思います。

Windowsにはiniファイルの読み込み・書き込みに関するAPI(命令群)が用意されているのですが、 これらは残念ながら直接WSHからは使えません。 こーゆー時、困りますよねー。そんな時!

のぶ代式バックドロップ〜」(ドラちゃん)

と、いう事で、自分で作っちゃえばそれほど難しい処理でもありません。
(何 が 『 と い う 事 で 』 な の か)

とりあえず、iniファイルって大体こんな書き方だったりします。

[school]
name=Wakame

[club]
name=sexy commando
memo=mehoho-burusasan S

要するに、[文字列]から次の[文字列]までがカテゴリっぽいものでその間に、 キー=値みたいな感じで複数行来る、と。(超適当)

まあ、そんな感じで作ってみたのが、コレ。

'Iniファイル情報取得
Function GetIniFileInfo(filepath)
  Dim objFSO  'FileSystemObject
  Dim objInfo  'iniファイル用Dictionary
  Dim objFile  'iniファイル
  Dim strLine  'データ読み込み用
  Dim objCat  'カテゴリ用Dictionary
  Dim strCat  'カテゴリ名
  Dim arrValue'キーと値の配列
  
  Set objFSO = CreateObject("Scripting.FileSystemObject")
  Set objInfo = CreateObject("Scripting.Dictionary")
  
  'iniファイルが存在すればデータ取得
  If objFSO.FileExists(filepath) Then
    Set objFile = objFSO.OpenTextFile(filepath)
    
    Do Until objFile.AtEndOfStream
      strLine = Trim(objFile.ReadLine)
      
      'カテゴリを表す行か
      If Left(strLine,1) = "[" And Right(strLine,1) = "]" Then
        'Category
        strCat = Mid(strLine,2,Len(strLine) - 2)
        If Not objInfo.Exists(strCat) Then
          Set objCat = CreateObject("Scripting.Dictionary")
          objInfo.Add strCat,objCat
        End If
      ElseIf Instr(strLine,"=") > 1 And strCat <> "" Then
        'Key & Value
        arrValue = Split(strLine,"=")
        objInfo(strCat).Add Trim(arrValue(0)), _
              Trim(Mid(Join(arrValue,"="),Len(arrValue(0)) + 2))
      End If
    Loop
    
    objFile.Close
  End If
  
  Set GetIniFileInfo = objInfo
  
  Set objFile = Nothing
  Set objCat = Nothing
  Set objInfo = Nothing
  Set objFSO = Nothing
End Function

以前やったファイル読み込みに毛が生えたみたいなもんです。 指定されたファイルを先頭から1行ずつ読んでいって、配列やDictionaryに格納しています。

はい、又変なのが出てきました。まず、配列についていつものように超適当に説明します。 配列とは変数の集合体みたいなもんです。 通常、変数には1つの値しか入れられませんが、配列にすると 複数の値が格納できます。 こんな感じ。

Dim arr(2)
Dim i
 
arr(0) = 10
arr(1) = 20
arr(2) = 30
 
For i = 0 To 2
    MsgBox arr(i)
Next

要するにカッコ内に個数をつけて宣言しておくと、その個数分値を格納できますよ、 と言うことです。ちなみにカッコ内の数字は0から始まりますので、2で宣言した場合、 格納できる値の数は3つになります。

この配列という機構、便利なのですが、以下のような不便さもあります。

  • 最初に配列の数が決まってないといけない
  • 値しか格納できない

プログラム中で配列の数がその行に来るまで分からない場合には不便ですし、 arr(1)に金額を入れたとしても、後から"arr(1)"と言う変数名を見ただけでは、 何を表しているのかさっぱりです。

で、その辺を解決しているのがDictionaryオブジェクトです。

  • 動的に格納する値の数を変更できる
  • 値に対しラベルを付加することができる

と言う特徴を持っています。こんな感じ

Dim dic
 
Set dic = CreateObject("Scripting.Dictionary")
dic.Add "name","マサル"
dic.Add "hair","ステキカット"
dic.Add "house","布がかかってる"
 
MsgBox dic("hair")

と、言った感じでAddでどんどん足していけると同時にラベル(key)を付ける事ができるので 後でわかりやっす!!みたいなところがあります。

では、やっとプログラムの説明です。先程も書いたように、

Do Until objFile.AtEndOfStream
   strLine = Trim(objFile.ReadLine)
   '色々処理・・・
Loop

の部分でiniファイルの内容を1行ずつ読んで strLineに入れています。

で、読み込んだ行がカテゴリを表す場合、つまり、

Left(strLine,1) = "[" And Right(strLine,1) = "]"

だった場合、要するに"["で始まって"]"で終わっている場合、

strCat = Mid(strLine,2,Len(strLine) - 2)
If Not objInfo.Exists(strCat) Then
    Set objCat = CreateObject("Scripting.Dictionary")
    objInfo.Add strCat,objCat
End If

既に初期処理で作成してあるDictionary、objInfoに更に新たなDictoraryを カテゴリ名で登録しています。 objInfo.Exist() で、Dictionaryに同名のkeyが既に登録されているかを判断します。 要するに、同じカテゴリ名が複数iniファイルに書いてある場合は めんどくさいので無視してます

で、その行がカテゴリではなくキーと値を表す行の場合、つまり、

Instr(strLine,"=") > 1 And strCat <> ""

だった場合、要するに行中に"="があって、カテゴリ行より後にある場合、

arrValue = Split(strLine,"=")
objInfo(strCat).Add Trim(arrValue(0)), _
    Trim(Mid(Join(arrValue,"="),Len(arrValue(0)) + 2))

該当のカテゴリ用Dictionaryに"="以前をキー、以降を値として登録しています。

Split()は、文字列を特定の文字列で区切って配列を返す関数です。

Split(対象文字列,区切りに使用する文字列)

今回の場合は、"="で区切って文字列を配列にしてます。 例えば、"name=マサル"であった場合、 arr(0)は"name"、arr(1)は"マサル"となります。

実は、多くの場合は、

arrValue = Split(strLine,"=")
objInfo(strCat).Add arrValue(0),arrValue(1)

と言う簡単なコードで済むんですが、該当の行の内容が、

name=マ=サ=ル

と、言う内容だった場合、値は"マ=サ=ル"のはずなのに、arrValue(1)で 取ってしまうと、"マ"になってしまいます。 なので、

Mid(Join(arrValue,"="),Len(arrValue(0)) + 2)

と、して再度連結して、最初の"="以降の全ての文字列を取得しているわけです。 Join()はSplit()の逆で、配列を指定された区切り文字を使って1つの文字列に 連結する関数です。

カテゴリ、もしくはキー&値の行以外(空白行等)は無視されます。 この調子で進んでいくと最終的にはiniファイルの内容を含んだ1つのDictionaryが作成されます。関数は結果としてこのDictionaryを返します。

この自作関数でサンプルとして書いた上記のiniファイルの内容を読み込むとこうなります。

Set objInit = GetIniFileInfo("C:\sample.ini")
 
MsgBox objInit("school")("name")
MsgBox objInit("club")("name")
MsgBox objInit("club")("memo")

それぞれ、wakame,sexy commando,mehoho-burusasan Sを表示します。 objInitはDictionaryなので、その中の1つ"school"を取り出すと、 その中身も又Dictionaryなので、そのまま"name"を取り出せる、と言う寸法です。 もちろん、

MsgBox objInit("school")("name")

の部分を

Set objSchool = objInit("school")
MsgBox objSchool("name")

としても同じです。

こんな感じで、専用のAPIなんぞなくてもテキスト処理でiniファイルなんて結構読めちゃいます。CSVやタブ区切り等のその他の定型ファイルも似たような仕組みで自在に取り出せますわ。

今回はこんな感じで。 次回はどーしましょうか。次回こそXML書き込みやりますかなぁ。。。

この記事は訳に立ちましたか?

選択肢 投票
はい 137  
いいえ 25  

  • 今回結構テキトーに書いたので分からないところがあったりしたら、ここに書くなり、質問してください。 -- メソ 2004-12-23 (木) 13:55:42
  • 何だか、幾つか「続きが読みたい」って要望があるようで、ありがとうございます。何か考えてみます。 -- メソ 2006-03-27 (月) 22:13:16
  • VBS使ったお仕事中に偶然こちらを発見しました。おかげで助かりました。多謝。 -- たろすけ? 2006-04-04 (火) 16:21:32
  • お役に立てて何よりです。またお役に立てるように、引き続き何か書いていきたいと思います。 -- メソ 2006-04-04 (火) 21:12:57
  • 第7章、書いてみました。 -- メソ 2006-04-06 (木) 17:49:34
  • 最後の、この記事は役に立ちましたか?…ではないので「いいえ」を選択してしまいそうです。 -- 2014-07-29 (火) 09:54:05

URL B I U SIZE Black Maroon Green Olive Navy Purple Teal Gray Silver Red Lime Yellow Blue Fuchsia Aqua White