プログラム・ソースの要点

植生データベース システムで使用している データ構造 + アルゴリズム = プログラム を公開。
使用しているコンパイラは、Object Pascal (Borand Delphi Version 6)

データレコードとファイルレコードのイメージ

データのレコード

インデックス・ファイル(xxxxx.fvi) は 長さ256bytes のランダムアクセスファイル
植物データ・ファイル (xxxxx.fvd) は 長さ512bytesのランダムアクセスファイル
  1. それぞれ、1行の長さ254、510bytesのテキストファイルとして読むこともできる
  2. ファイルのレコード番号0はダミー、レコード番号1以降がデータのレコード番号に相当
  3. インデックス・ファイルの末尾に、植物データファイルの最初のレコード番号が入る
  4. 植物データファイルの末尾には、続きとなる植物データファイルのレコード番号が入る
  5. 続きとなる植物データファイルのレコード番号が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 }