プログラム・ソースの要点
植生データベース システムで使用している データ構造 + アルゴリズム = プログラム を公開。
使用しているコンパイラは、Object Pascal (Borand Delphi Version 6)
データレコードとファイルレコードのイメージ
インデックス・ファイル(xxxxx.fvi) は 長さ256bytes のランダムアクセスファイル
植物データ・ファイル (xxxxx.fvd) は 長さ512bytesのランダムアクセスファイル
- それぞれ、1行の長さ254、510bytesのテキストファイルとして読むこともできる
- ファイルのレコード番号0はダミー、レコード番号1以降がデータのレコード番号に相当
- インデックス・ファイルの末尾に、植物データファイルの最初のレコード番号が入る
- 植物データファイルの末尾には、続きとなる植物データファイルのレコード番号が入る
- 続きとなる植物データファイルのレコード番号が0のとき、1レコードの終わりとなる
その1.レコードデータの変数 (FVT4 の例)
{ データを納める変数 }
HeaderFile : File of RelHead; { Main Record File }
RelHead = Record { 256 bytes PlantSet Header }
LHead : LongItem; { 8 bytes x 8項目 = 64 データ作成日から地理区画まで }
SHead : ShortItem; { 4 bytes x 23項目 = 92 標高から出現種数まで }
IKai : char; { 0, 1, 5, 7 のどれか = 1 bytes }
ICov : char; { 0, 1, 2, 3 のどれか = 1 bytes }
Invst : Mozi10; { = 10 bytes 調査者名 }
Remrk : array [1..80] of char; { = 80 bytes 備考 }
RIdx : Mozi6; { = 6 bytes 続 きとなる植物データファイルのレコード番号 }
EMark : Mozi2; { cr/lf = 2 bytes }
end;
PlantFile : File of PlantRec; { Sub Record File }
PlantRec = Record { 512 bytes plants description }
Plt : array [1..12] of Onesp; { 12種 x 4 2 bytes = 504 bytes, species data }
NIdx : Mozi6; { = 6 bytes 続きのレコード番号 }
EMark : Mozi2; { cr/lf = 2 bytes }
end;
PlantSet : array of TabSp;
TabSp = record { 35 bytes plant data }
nam : Mozi28; { 28 bytes 植物名 }
dby : ByteDataSet; { 7 階層 x 1 byte = 7 bytes }
end;
その2.レコードデータの書き出し (FVD4 の例)
{ ファイルからレコードを読む関数 }
Function WriteRecord (var Fh: HeaderFileType; var Fp: PlantFileType; rc: integer): boolean;
{ レコード番号 rc に書き出す }
var plantpos, np, writeplantnum : integer; { 局所変数 }
ok : boolean;
begin
ok := true; { ファイルエラーチェックのため }
try { ヘッダーレコード }
if rc > MaxReleveNum then begin { 追加レコードの場合 }
MaxPlantRec := MaxPlantRec + 1;
NextPoint[1] := MaxPlantRec;
for np := 2 to High(NextPoint) do NextPoint[np] := 0;
end;
np := 1; { 書き出すレコードの頭 }
Seek(Fh, rc); { 書き出し頭位置へ }
IntToText6(NextPoint[np], DataofHead.RIdx); { 続きデータの位置をセット }
Write(Fh, DataofHead); { インデックスレコードを書き出す }
{ 以下、植物レコードへ }
plantpos := 1; { 書き出す植物の頭位置 }
while plantpos <= ActualNSp do begin { 残り植物ある限り、繰り返す }
writeplantnum := ActualNSp - plantpos + 1;
if writeplantnum > 12 then writeplantnum := 12;
FillChar(DataofPlant, 504, ' '); { 植物部分クリア }
Move(PlantSet[plantpos], DataofPlant.plt[1], 504);
plantpos := plantpos + writeplantnum; { 次の植物位置レコード番号を決める }
if plantpos <= ActualNSp then begin { さらに続く }
if NextPoint[np+1] = 0 then begin
MaxPlantRec := MaxPlantRec + 1;
NextPoint[np+1] := MaxPlantRec;
end;
end
else NextPoint[np+1] := 0; { ここで終わりになる }
IntToText6(NextPoint[np+1], DataofPlant.NIdx); { 次のレコード番号をセットする }
DataofPlant.EMark := CrLf;
try
Seek(Fp, NextPoint[np]); { 植物データのレコード位置をセット }
Write(Fp, DataofPlant); { 植物データのレコードを書き出す }
np := np + 1;
except
ok := false;
end;
end; { of while plantpos <= ActualNSp }
PlotChanged := false;
TableChanged := false;
except
ok := false;
end;
CloseFile(Fh); { 安全のため、一度ファイルを閉じる }
CloseFile(Fp);
{ 再オープン }
ReSet(Fh);
ReSet(Fp);
MaxReleveNum := FileSize(Fh) - 1; { 最大レコード数を再セットしておく }
MaxPlantRec := FileSize(Fp) - 1;
Result := ok;
Form1.EditN.Caption := IntToStr(Rec); { 現在レコードを表示 }
Form1.LabelMaxRec.Caption := IntToStr(MaxReleveNum); { 最大レコードを表示 }
Form1.Refresh;
end; { of WriteRecord }
その3.レコードデータの読み込み (FVD4, FVT4 の例)
{ ファイルからレコードを読む関数 }
function ReadRecord(rc: integer): boolean; { レコード番号 rc のレコードを読む関数 }
var pn, plantpos, nextpos : integer; { 局所変数 }
begin
try
Seek (HeaderFile, rc); { fvi ファイルのレコード番号 rc }
Read (HeaderFile, DataofHead); { データを変数 DataofHead に読み込む }
Kai := StrToInt (DataofHead.IKai); { 階層数を得る }
Hcv := StrToInt (DataofHead.ICov); { 優占度級の桁数を得る }
NumberOfSpecies := StrToInt (DataofHead.SHead[30]); { 種数を得る }
while NumberOfSpecies > MaxSpNum do
MaxSpNum := NumberOfSpecies + 4; { 最大種数の枠を種数+4とする }
SetLength (PlantSet, MaxSpNum+1); { 植物のデータセット数を最大種数+4に設定 }
nextpos := StrToInt (DataofHead.RIdx); { データの最初のレコードを得る }
if nextpos = 0 then NumberOfSpecies := 0; { データが終わりなら、種数は0となる }
ClearPlantSetData; { 植物データセットを空にする }
plantpos := -12; { 最初の植物位置が0なので、ここは-12 }
while (nextpos > 0) do begin { 次のレコード位置が0になるまで、続ける }
plantpos := plantpos + 12; { 1レコードで12種だから、ポインタを12進める }
Seek(PlantFile, nextpos); { レコード番号 nextpos に位置づけ }
Read(PlantFile, DataofPlant); { 植物のデータセット(12種分)を読む }
for pn := 1 to 12 do begin { 植物のデータセットから データ変換 }
PlantSet[plantpos + pn].nam := DataofPlant.Plt[pn].nam; { 植物名 }
PlantSet[plantpos + pn].dby := TwoToByte(DataofPlant.Plt[pn].dom);
{ 2バイトの優占度を1バイトの数値に変える }
end;
nextpos := StrToInt(DataofPlant.NIdx); { 次の植物レコード位置を得る、0でなければwhile 文を繰り返す }
end; { of while next p }
Result := true; { データは正常に読み込めた }
except
Result := false; { データの読み込みに異常があった }
end;
end; { of ReadRecord }