ファイルの扱い方(配列の応用)
今回は私が発見した配列の応用法です。
これは、マニュアルのどこかに書いてあるかも知れないのですが、今のところあの分厚い本のどこかに書かれているかということは確認していません。もし、マニュアルに記述がなければ違うバージョンのVBでは使えなくなるかも知れない機能なのでご注意下さい。
しかし、ここで紹介する手法は非常に強力かつ便利で手抜きできる方法なので、VB4.0をお持ちの方は一度お試し下さい。
例えば、アドレス帳なんかのプログラムで複数件のデータを保存したいときはどうするでしょうか?
一般的なBASICの教科書では、シーケンシャルファイルやランダムファイルに保存すると書かれていると思うのですが、これはファイル内のデータが全て同じフォーマットのレコードである場合には簡単に実現できます。では、そのファイルに住所録フォーマットにそぐわないデータ、例えばアドレス帳の持ち主の情報やファイルがいつ変更されたのか等々を一緒に保存したい時はどうすればいいのでしょう。
一般的には、ファイルに保存したいデータというのは、住所録のような定型的なデータより不定型なデータあるいは部分的に定型的なデータの方が多いと思います。
今回の講座では部分的に定型的(レコード)なデータの保存と復元の方法を解説します。
今回の講座のサンプルは、 ここを押すとダウンロード
できます。
例題のフォームはこんな感じです。
プログラムを実行すると、ランダムの数字がランダム数にリストに追加されます。
このときの乱数は配列に保存されるのですが、配列の下限と上限もランダムに作るので配列のサイズもランダムです。
ボタン"Save"でこの配列を保存し、"Load"でファイルから読み込んだ配列データを右側のリストに表示します。
"RND"は配列を初期化し、別の乱数を埋め込みます。
Private SMax As Integer, LMax As Integer '変数宣言
Private SMin As Integer, LMin As Integer
Private Type Val_def '変数のレコード
Data() As Integer
End Type
Private SVal As Val_def 'これはレコード型
Private LVal As Val_def
整数配列をユーザ定義型(レコード)に入れ込んでいるのは後の布石です。
Private Sub Form_Load()
Randomize Time / 2 '乱数の初期化
SMax = Rnd * 100 + 10 'Maxを決める
SMin = Rnd * 10 + 1 'Min
ReDim SVal.Data(SMin To SMax)
list1.Clear
For i = SMin To SMax
SVal.Data(i) = Rnd * 100
list1.AddItem SVal.Data(i)
Next
label1 = "Min =" + Str(SMin)
label3 = "Max =" + Str(SMax)
End Sub
プログラムの最初で乱数を作って、配列に格納しています。
レコード型を使うことで、
SVal.Data(i) = Rnd * 100
などと、うざったいことをしていますがこれは後ほどの恩恵を受けるためです。
この関数は"RND"ボタンからも呼ばれています。
ここでは、配列の底(下限)と天井(上限)もランダムに設定していることに注意しておいてください。
Private Sub Command1_Click()
'SValレコードを一気に保存
Open "val.tmp" For Binary Access Write As #1
Put #1, , SVal
Close #1
End Sub
データの保存はたったのこれだけです。何となくレコード型のありがたさが見えてきましたか?
Private Sub Command2_Click()
'LValレコードを一気に読み込む
Open "val.tmp" For Binary Access Read As #1
Get #1, , LVal
Close #1
LMax = UBound(LVal.Data) 'アイテム数
LMin = LBound(LVal.Data)
List2.Clear '表示
For i = LMin To LMax
List2.AddItem LVal.Data(i)
Next
Label2 = "Min =" + Str(LMin)
Label4 = "Max =" + Str(LMax)
End Sub
レコード型で括ったデータ(SVal,LVal)はこのように一回のアクセスで書き込み&読み込みができます。
さらに嬉しいことに、一括保存したレコードはそのメンバ(ここではData())が配列であれば、底と天井まで復元してくれることです。
プログラムから見れば、ユーザーが保存したデータの件数というのは不確定なので、一般的にはファイルの先頭部分にそのファイルに何件のデータが含まれているか?ということを記録してやる必要があります。(但し、シーケンシャルファイルでEOFチェックする時や、ランダムアクセスファイルという固定長レコードの場合は別ですが)
また、データを読み込むときにもForループなどで件数分データを読み込む処理が必要です。
しかし、上記の様に一括で保存&読込むことができれば手間が大幅に減りますよね。更に、Forループを回して保存&読込みする場合に比べてファイルI/Oの時間も短くなります。
最後に
最初にも断りましたが、ここで説明した内容はマニュアルには載っていない(ざっと調べた限りでは見つけられませんでした)ことです。もしかしたらBASICの基本的な手法の部類に入るのかも知れませんが、私の知る限りでは教科書にも載っていないと思います。
このことは何を表しているかというと、上記の機能がVBで公式にサポートされていない機能なのかも知れない、すなわち将来のバージョンのVBでは使えないかも知れないということです。
しかし、私はこの機能を発見したことでプログラミング上でも実行速度の面でも少なからぬ恩恵を受けることができました。
例題のデータ型は非常に簡単な構造ですが、もちろんユーザ定義型に他のユーザ定義型を入れ子にすることもできます。したがって、もっと複雑なデータ型でも簡単に扱えるということです。皆さんの応用を期待します。