第8章 ファイル入出力機能

8.1 概要

ここでは、SIT COBOLがサポートしている、順ファイル・行順ファイル・索引ファイルについて具体的な書き方について記述する。

8.2 順ファイル

順ファイル(Sequential File)とは、レコード(データのひとまとまり)を順番に格納し、順番通りにアクセスするファイル形式である。データは一列に並んでおり、先頭から順番に読み書きすることで処理される。

この形式の最大の特徴は、データへのアクセスが順序通りにしか行えない点である。特定のレコードに直接アクセスすることはできず、常に先頭から順番に処理を行う必要がある。

8.2.1 順ファイルの用途と特徴

順ファイルは、以下のような用途で広く使用されている。

順ファイルの主な特徴は以下の通り:

一方で、特定のレコードへの直接アクセスができないという制約もあるため、用途に応じた使い分けが求められる。

8.2.2 順ファイル例(1)

まず、順ファイルを作成する例を見ていく。
サンプルとして作成するファイルは、5種類の果物の名前とその数量を持つシンプルなファイルである。

(サンプルプログラム名:順ファイルの作成例.cob)

000000 IDENTIFICATION DIVISION.
000010 PROGRAM-ID. SEQFILE001.
000020 ENVIRONMENT DIVISION.
000030 INPUT-OUTPUT SECTION.
000040 FILE-CONTROL.
000050     SELECT 果物ファイル ASSIGN TO "./果物ファイル.txt"
000060            ORGANIZATION IS SEQUENTIAL.
000070 DATA DIVISION.
000080 FILE SECTION.
000090 FD 果物ファイル.
000100 01 果物レコード.
000110    02 名前 PIC N(10).
000120    02 数量 PIC 9(5).
000130 WORKING-STORAGE SECTION.
000140 01 果物データ.
000150    02 PIC N(10) VALUE NC"リンゴ".
000160    02 PIC 9(5)  VALUE 10.
000170    02 PIC N(10) VALUE NC"オレンジ".
000180    02 PIC 9(5)  VALUE  5.
000190    02 PIC N(10) VALUE NC"メロン".
000200    02 PIC 9(5)  VALUE 20.
000210    02 PIC N(10) VALUE NC"バナナ".
000220    02 PIC 9(5)  VALUE  8.
000230    02 PIC N(10) VALUE NC"イチゴ".
000240    02 PIC 9(5)  VALUE 12.
000250 01 果物データ2 REDEFINES 果物データ.
000260    02 果物テーブル OCCURS 5.
000270       03 名前 PIC N(10).
000280       03 数量 PIC 9(5).  
000290 01 I PIC 9.
000300 PROCEDURE DIVISION.
000310 MAIN00.
000320*    ファイルのオープン
000330     OPEN OUTPUT 果物ファイル.
000340*    5つの果物データをファイルに書き出し
000350     PERFORM VARYING I FROM 1 BY 1 UNTIL I > 5
000360         MOVE 果物テーブル(I) TO 果物レコード
000370         WRITE 果物レコード
000380     END-PERFORM.
000390*    ファイルのクローズ
000400     CLOSE 果物ファイル.
000410     STOP RUN.

(1) ファイルの定義

まず、果物ファイルの定義は、環境部(ENVIRONMENT部)の入出力節(INPUT-OUTPUT節)のファイル管理段落(FILE-CONTROL段落)の中にSELECT句を書くことによって行う。

000020 ENVIRONMENT DIVISION.
000030 INPUT-OUTPUT SECTION.
000040 FILE-CONTROL.
000050     SELECT 果物ファイル ASSIGN TO "./果物ファイル.txt"
000060            ORGANIZATION IS SEQUENTIAL
000070            ACCESS MODE IS SEQUENTIAL.

ファイル名は、SELECT句の直後に書く。また、ファイル編成が順編成であることは、「ORGANIZATION IS SEQUENTIAL」にて宣言する。(ORGANIZATION句を書かない場合の既定値は順編成なので書かなくともよい)

また、アクセスモードについてはACCESS MODE句で指定するが、順ファイルの場合は順呼出し(SEQUENTIAL)のみである。(ACCESS句を書かない場合の既定値は順呼出しなので書かなくともよい)

また、ファイルの実体については、「ASSIGN TO」 の直後に記述する。
ここでは”./果物ファイル.txt”が指定されているので、カレントディレクトリ配下(*1)に「果物ファイル.txt」が作られる。

(*1) 実行するCOBOLプログラムが存在するディレクトリがカレントディレクトリとなる。絶対パスも指定可である。

なお、ファイルの実体を環境変数によって指定することも可能である。例えば、“FILE_PATH”という環境変数にファイルの実体が指定されている場合は、次のように指定する。

000050     SELECT 果物ファイル ASSIGN TO "FILE_PATH"
000060            ORGANIZATION IS SEQUENTIAL
000070            ACCESS MODE IS SEQUENTIAL.

SIT COBOLは、OPEN文の実行時、ASSIGN TOの直後に書かれた定数と同じ名前の環境変数が存在するか確認し、存在する場合にはその環境変数からファイルを実体を取得し存在しない場合は、書かれた定数の値がファイルの実体であるとみなす。

さらには、次のようにデータ名で指定することも可能である。例えば、ファイルパスというデータ名でファイルの実体を指定するのであれば、次のように指定する。

000050     SELECT 果物ファイル ASSIGN TO ファイルパス
000060            ORGANIZATION IS SEQUENTIAL
000070            ACCESS MODE IS SEQUENTIAL.
  :
000000 WORKING-STORAGE SECTION.
000000 01 ファイルパス PIC X(255).
  :
000000     MOVE "./果物ファイル.txt" TO ファイルパス.
000000     OPEN OUTPUT 果物ファイル.
  :

SIT COBOLは、OPEN文の実行時、ASSIGN TOの直後に書かれたデータ名’ファイルパス’の値をファイルの実体であるとみなす。

(2) ファイルのレコード構造の定義

一方、ファイルがどのようなレコード構造を持つかは、データ部(DATA部)の、ファイル節(FILE節)に記述する。

000080 DATA DIVISION.
000090 FILE SECTION.
000100 FD 果物ファイル.
000110 01 果物レコード.
000120    02 名前 PIC N(10).
000130    02 数量 PIC 9(5).

FDの次にファイル名を記述し、その次にレコード構造を記述する。
ここでは、’名前’というデータ名と、’数量’というデータ名を持つ’果物レコード’が定義されている。果物レコードの大きさは、日本語10文字と英数字5文字(5バイト)を足し合わせた大きさである。

(注意) SIT COBOLは、ファイル中のレコードには、用途がDISPLAYである英数字項目、英数字編集項目、外部十進項目、数字編集項目、日本語項目、日本語編集項目のみしか定義できないようにしている。これは、COBOLを学習するにあたり、ファイルの中身をエディタ等で開いて確認できるようにすることに優先順位をおいているためである。

(3) ファイルのオープン

ファイルを開くには、OPEN文を使用する。

000330*    ファイルのオープン
000340     OPEN OUTPUT 果物ファイル.

オープンモードは、OPEN文の直後に記述する。この場合は、OUTPUTモードなので、ファイルが存在すれば上書きをし、存在しなければ1から作成することを指示している。

(4) データの出力

ファイルにデータを書き込むには、WRITE文を使用する。
下記は、果物テーブル(1)~果物テーブル(5)までのデータを順次果物レコードに転記し、WRITE文でレコードの内容をファイルに出力している。

000350*    5つの果物データをファイルに書き出し
000360     PERFORM VARYING I FROM 1 BY 1 UNTIL I > 5
000370         MOVE 果物テーブル(I) TO 果物レコード
000380         WRITE 果物レコード
000390     END-PERFORM.

MOVE文とWRITE文は次のようにFROM指定を使用して1文にすることもできる。

00370         WRITE 果物レコード FROM 果物テーブル(I)

(5) ファイルのクローズ

ファイルを閉じるには、CLOSE文を使用する。

000400*    ファイルのクローズ
000410     CLOSE 果物ファイル.

(6) 実行結果

上記のプログラムを実行すると次のようなファイルが作成される。
(Windows上のコマンドプロンプトでcatコマンドで確認した例。“□”は日本語の空白を示す)

> cat .\果物ファイル.txt
リンゴ□□□□□□□00010オレンジ□□□□□□00005メロン□□□□□□□00020バナナ□□□□□□□00008イチゴ□□□□□□□00012
>

8.2.3 順ファイル例(2)

次に、順ファイルを読み出す例を見ていく。
参照するファイルは、例(1)で作成した”果物ファイル.txt”である。

(サンプルプログラム名:順ファイルの入力例.cob)

000000 IDENTIFICATION DIVISION.
000010 PROGRAM-ID. SEQFILE002.
000020 ENVIRONMENT DIVISION.
000030 INPUT-OUTPUT SECTION.
000040 FILE-CONTROL.
000050     SELECT 果物ファイル ASSIGN TO "./果物ファイル.txt".
000060 DATA DIVISION.
000070 FILE SECTION.
000080 FD 果物ファイル.
000090 01 果物レコード.
000100    02 名前 PIC N(10).
000110    02 数量 PIC 9(5).
000120 WORKING-STORAGE SECTION.
000130 01 ヘッダ.
000140    02          PIC N(10) VALUE NC"果物名".
000150    02          PIC N(3)  VALUE NC"個数".
000160 01 罫線        PIC X(25) VALUE ALL "-".
000170 01 果物データ.
000180    02 果物名   PIC N(10).
000190    02 個数     PIC ZZZZ9.
000200 01 合計データ.
000210    02          PIC N(10) VALUE NC"合計".
000220    02 合計     PIC ZZZZ9.
000230 PROCEDURE DIVISION.
000240 MAIN00.
000250*    ファイルのオープン
000260     OPEN INPUT 果物ファイル.
000270*    初期化
000280     MOVE 0 TO 合計.
000290*    ヘッダ出力
000300     DISPLAY ヘッダ.
000310     DISPLAY 罫線.
000320*    ファイルから果物データをAT ENDとなるまで読み込む
000330     PERFORM FOREVER
000340         READ 果物ファイル
000350         AT END
000360           EXIT PERFORM
000370         NOT AT END
000380           MOVE 名前 OF 果物レコード TO 果物名
000390           MOVE 数量 OF 果物レコード TO 個数
000400           DISPLAY 果物データ
000410           ADD  数量 OF 果物レコード TO 合計
000420         END-READ
000430     END-PERFORM.
000440*    フッタの出力
000450     DISPLAY 罫線.
000460     DISPLAY 合計データ.
000470*    ファイルのクローズ
000480     CLOSE 果物ファイル.
000490     STOP RUN.

ファイルの定義、ファイルのデータ後続については例(1)と同じなので省略する。

(1) ファイルのオープン

ファイルを開くには、OPEN文を使用する。

000250*    ファイルのオープン
000260     OPEN INPUT 果物ファイル.

この場合は、INPUTモードで開いている。ファイルが存在しない場合にはエラーとなる。

(2) データの入力

ファイルからデータを読み込むには、READ文を使用する。
ここで、WRITE文に指定するのはレコード名であるのに対し、READ文に指定するのはファイル名であることに注意されたい。

下記は、FOREVER指定(無限指定)のPERFORM文によって繰り返し、果物ファイルから1件ずつレコードを読み込む。そして、AT ENDとなった時点(データが終了した時点)でPERFORM文から抜ける(EXIT PERFORM)。

000320*    ファイルから果物データをAT ENDとなるまで読み込む
000330     PERFORM FOREVER
000340         READ 果物ファイル
000350         AT END
000360           EXIT PERFORM
000370         NOT AT END
000380           MOVE 名前 OF 果物レコード TO 果物名
000390           MOVE 数量 OF 果物レコード TO 個数
000400           DISPLAY 果物データ
000410           ADD  数量 OF 果物レコード TO 合計
000420         END-READ
000430     END-PERFORM.

レコードの読み込みが成功した場合は、NOT AT END句の無条件文が実行される(000380-000410行)。
ここでは、果物レコードの名前と数量が、それぞれ’果物名’、’個数’に転記され、さらに数量が、’合計’に加算されている。すなわち、’合計’には最終的に全果物の合計数量が設定される。

なお、次のように、INTO指定のREAD文により、レコードの読み込みが成功したときにレコード領域のデータを転記することもできる。

000340         READ 果物ファイル INTO 果物データ
000350         AT END
000360           EXIT PERFORM
000370         NOT AT END
000400           DISPLAY 果物データ
000410           ADD  数量 OF 果物レコード TO 合計
000420         END-READ

(3) ファイルのクローズ

ファイルを閉じるには、例(1)と同じくCLOSE文を使用する。

000470*    ファイルのクローズ
000480     CLOSE 果物ファイル.

(4) 実行結果

さて、このプログラムを走行させると、次のような帳票が出力される。

果物名       個数 
-------------------------
リンゴ          10
オレンジ          5
メロン          20
バナナ           8
イチゴ          12
-------------------------
合計           55

先頭の見出しおよび罫線は以下の2つのDISPLAY文で出力されている。

000290*    ヘッダ出力
000300     DISPLAY ヘッダ.
000310     DISPLAY 罫線.

続く明細データは次のDISPLAY文で出力されている。

000400           DISPLAY 果物データ

最後の罫線および合計行は次のDISPLAY文で出力されている。

000440*    フッタの出力
000450     DISPLAY 罫線.
000460     DISPLAY 合計データ.

8.2.4 順ファイル例(3)

次に、順ファイルのレコードを書き換えたり削除したりする例を見ていく。
参照するファイルは、例(1)で作成した”果物ファイル.txt”である。

以下のプログラムは、オレンジの数量を15に変更し、またバナナレコードを削除するプログラムである。
なお、000450行以降は、更新したデータ内容や削除がうまくいっているかを確認するために例(2)のプログラムのロジックを使用して帳票出力をしている。

(サンプルプログラム名:順ファイルの更新例.cob)

000000 IDENTIFICATION DIVISION.
000010 PROGRAM-ID. SEQFILE003.
000020 ENVIRONMENT DIVISION.
000030 INPUT-OUTPUT SECTION.
000040 FILE-CONTROL.
000050     SELECT 果物ファイル ASSIGN TO "./果物ファイル.txt".
000060 DATA DIVISION.
000070 FILE SECTION.
000080 FD 果物ファイル.
000090 01 果物レコード.
000100    02 名前 PIC N(10).
000110    02 数量 PIC 9(5).
000120 WORKING-STORAGE SECTION.
000130 01 ヘッダ.
000140    02          PIC N(10) VALUE NC"果物名".
000150    02          PIC N(3)  VALUE NC"個数".
000160 01 罫線        PIC X(25) VALUE ALL "-".
000170 01 果物データ.
000180    02 果物名   PIC N(10).
000190    02 個数     PIC ZZZZ9.
000200 01 合計データ.
000210    02          PIC N(10) VALUE NC"合計".
000220    02 合計     PIC ZZZZ9.
000230 PROCEDURE DIVISION.
000240 MAIN00.
000250*    ファイルのオープン
000260     OPEN I-O 果物ファイル.
000270*    ファイルから果物データをAT ENDとなるまで読み込む
000280     PERFORM FOREVER
000290         READ 果物ファイル
000300         AT END
000310           EXIT PERFORM
000320         END-READ
000330         IF 名前 OF 果物レコード = NC"オレンジ"
000340           MOVE 15 TO 数量 OF 果物レコード
000350           REWRITE 果物レコード
000360         END-IF
000370         IF 名前 OF 果物レコード = NC"バナナ"
000380           DELETE 果物ファイル
000390         END-IF
000400     END-PERFORM.
000410     
000420*    ファイルのクローズ
000430     CLOSE 果物ファイル.
000440     
000450*    再オープン
000460     OPEN INPUT 果物ファイル.
000470     
000480*    初期化
000490     MOVE 0 TO 合計.
000500*    ヘッダ出力
000510     DISPLAY ヘッダ.
000520     DISPLAY 罫線.
000530*    ファイルから果物データをAT ENDとなるまで読み込む
000540     PERFORM FOREVER
000550         READ 果物ファイル
000560         AT END
000570           EXIT PERFORM
000580         NOT AT END
000590           MOVE 名前 OF 果物レコード TO 果物名
000600           MOVE 数量 OF 果物レコード TO 個数
000610           DISPLAY 果物データ
000620           ADD  数量 OF 果物レコード TO 合計
000630         END-READ
000640     END-PERFORM.
000650*    フッタの出力
000660     DISPLAY 罫線.
000670     DISPLAY 合計データ.
000680*    ファイルのクローズ
000690     CLOSE 果物ファイル.
000700     STOP RUN.

ファイルと定義、レコード構造については例(1)(2)と同じであり省略する。

(1) ファイルのオープン

ファイルを開くには、OPEN文を使用する。

000250*    ファイルのオープン
000260     OPEN I-O 果物ファイル.

この場合は、I-Oモードで開いている。ファイルのデータの中身を更新したり削除したりするときはI-Oモードで開く必要がある。ない、存在しない場合にはエラーとなる。

(2) データの入力

ファイルからデータを読み込むには、READ文を使用する。READ文については例(2)で触れており、ここでは省略する。

000290         READ 果物ファイル
000300         AT END
000310           EXIT PERFORM
000320         END-READ

(3) データの更新

データの更新を行うには、REWRITE文を使用する。

000330         IF 名前 OF 果物レコード = NC"オレンジ"
000340           MOVE 15 TO 数量 OF 果物レコード
000350           REWRITE 果物レコード
000360         END-IF

上記では、果物レコードの名前が”オレンジであるとき、数量を15に更新してから、REWRITE文を実行している。
REWRITE文にはWRITE文と同じくレコード名を指定する必要がある。

(4) データの削除

データを削除するには、DELETE文を使用する。

000370         IF 名前 OF 果物レコード = NC"バナナ"
000380           DELETE 果物ファイル
000390         END-IF

上記では、果物レコードの名前が”バナナであるとき、DELETE文を実行している。
DELETE文にはREAD文と同じくファイル名を指定する必要がある。

なお、順ファイルのレコードを削除できるのは SIT COBOLの特別な機能である。

(5) ファイルのクローズ

ファイルを閉じるには、例(1)(2)と同じくCLOSE文を使用する。

000420*    ファイルのクローズ
000430     CLOSE 果物ファイル.

(6) 実行結果

さて、このプログラムを走行させると、データの更新・削除が行われたあと、000450行から再びファイルをINPUTモードでオープンしてレコードの読み込みを行っており、次のような帳票が出力される。

果物名       個数 
-------------------------
リンゴ          10
オレンジ         15
メロン          20
イチゴ          12
-------------------------
合計           57

オレンジの個数が15に変更されており、またバナナデータが削除されているのがわかる。

8.3 相対ファイル

相対ファイル(Relative File)は、COBOLのファイル編成の一つであり、各レコードが相対レコード番号(Relative Record Number)で識別される。
データの格納位置はレコード番号に基づいて直接アクセスできるため、順次アクセスだけでなく直接アクセスもサポートする。

8.3.1 相対ファイルの用途と特徴

相対ファイルは、レコード番号を使用してデータを直接または順番にアクセスするため、特定の用途に適している。

SIT COBOLは、相対ファイルを未サポート(サポート予定あり)であり、機能についての説明はここまでに留める。

8.4 索引ファイル

索引ファイル(Indexed File)は、COBOLにおけるファイル編成の一つであり、キー値を用いてレコードにアクセスする。各レコードには少なくとも1つの主キー(Primary Key)があり、必要に応じて複数の代替キー(Alternate Key)を持つことができる。

索引を使うことで、順次アクセス、ランダムアクセス、動的アクセスが可能となる。

8.4.1 索引ファイルの用途と特徴

索引ファイル(Indexed File)は、主キー(Primary Key)および代替キー(Alternate Key)を用いてデータにアクセスする仕組みを持つファイル編成形式である。主に以下の用途で利用される。

8.4.2 索引ファイル例(1)

まず、順ファイル例として作成した”果物ファイル”を索引ファイルとして作成する例を見ていく。

(サンプルプログラム名:索引ファイルの作成例.cob)

000000 IDENTIFICATION DIVISION.
000010 PROGRAM-ID. INDFILE001.
000020 ENVIRONMENT DIVISION.
000030 INPUT-OUTPUT SECTION.
000040 FILE-CONTROL.
000050     SELECT 果物ファイル ASSIGN TO "./果物ファイル.sqlite3"
000060            ORGANIZATION IS INDEXED
000070            RECORD KEY IS 商品番号 OF 果物レコード
000080            ACCESS MODE IS SEQUENTIAL.
000090 DATA DIVISION.
000100 FILE SECTION.
000110 FD 果物ファイル.
000120 01 果物レコード.
000130    02 商品番号 PIC 9(3).
000140    02 名前     PIC N(10).
000150    02 数量     PIC 9(5).
000160 WORKING-STORAGE SECTION.
000170 01 果物データ.
000180    02 PIC 9(3)  VALUE 101.
000190    02 PIC N(10) VALUE NC"リンゴ".
000200    02 PIC 9(5)  VALUE 10.
000210    02 PIC 9(3)  VALUE 102.
000220    02 PIC N(10) VALUE NC"オレンジ".
000230    02 PIC 9(5)  VALUE  5.
000240    02 PIC 9(3)  VALUE 103.
000250    02 PIC N(10) VALUE NC"メロン".
000260    02 PIC 9(5)  VALUE 20.
000270    02 PIC 9(3)  VALUE 104.
000280    02 PIC N(10) VALUE NC"バナナ".
000290    02 PIC 9(5)  VALUE  8.
000300    02 PIC 9(3)  VALUE 105.
000310    02 PIC N(10) VALUE NC"イチゴ".
000320    02 PIC 9(5)  VALUE 12.
000330 01 果物データ2 REDEFINES 果物データ.
000340    02 果物テーブル OCCURS 5.
000350       03 商品番号 PIC 9(3).
000360       03 名前     PIC N(10).
000370       03 数量     PIC 9(5).  
000380 01 I PIC 9.
000390 PROCEDURE DIVISION.
000400 MAIN00.
000410*    ファイルのオープン
000420     OPEN OUTPUT 果物ファイル.
000430*    5つの果物データをファイルに書き出し
000440     PERFORM VARYING I FROM 1 BY 1 UNTIL I > 5
000450         MOVE 果物テーブル(I) TO 果物レコード
000460         WRITE 果物レコード
000470     END-PERFORM.
000480*    ファイルのクローズ
000490     CLOSE 果物ファイル.
000500     STOP RUN.

(1) ファイルの定義

ファイルの定義は、順ファイルと同様に、環境部(ENVIRONMENT部)の入出力節(INPUT-OUTPUT節)のファイル管理段落(FILE-CONTROL段落)の中にSELECT句を書くことによって行う。

000020 ENVIRONMENT DIVISION.
000030 INPUT-OUTPUT SECTION.
000040 FILE-CONTROL.
000050     SELECT 果物ファイル ASSIGN TO "./果物ファイル.sqlite3"
000060            ORGANIZATION IS INDEXED
000070            RECORD KEY IS 商品番号 OF 果物レコード
000080            ACCESS MODE IS SEQUENTIAL.

ファイル名は、SELECT句の直後に書く。また、ファイル編成が索引編成であることは、「ORGANIZATION IS INDEXED」にて宣言する。

また、アクセスモードについてはACCESS MODE句で指定する。ここでは、順にデータを書き出しするだけなので、順呼出し(SEQUENTIAL)を指定している。

また、ファイルの実体については、「ASSIGN TO」 の直後に記述する。ここでは”./果物ファイル.sqlite3”が指定されているので、カレントディレクトリ配下(*1)に「果物ファイル.sqlite3」が作られる。

ここで、拡張子として「.sqlite3」を指定しているが、これは SIT COBOL が 索引ファイルを、SQLITE3データベースをベースとして作成しており、索引ファイルの実体がSQLITE3であることを明示するために指定している(*2)。しかし、実際には、拡張子は何を指定してもよい。

(*1) 実行するCOBOLプログラムが存在するディレクトリがカレントディレクトリとなる。絶対パスも指定可である。
(*2) 索引ファイルは、SQLITE3データベースでできているので、SQLITE3データベースをアクセスできるユーティリティーで索引ファイルのメンテナンス等を行うことができる。

索引ファイルにおいては、必ず主キーを指定する必要がある。主キーは「RECORD KEY」句で指定する。
ここでは、’商品番号 OF 果物レコード’を指定している。果物レコードで修飾しているのは、商品番号というデータ名が他にも使われており、一意にする必要があるためである。

なお、ファイルの実体を環境変数によって指定することも可能である。例えば、“FILE_PATH”という環境変数にファイルの実体が指定されている場合は、次のように指定する。

000050     SELECT 果物ファイル ASSIGN TO "FILE_PATH"
000060            ORGANIZATION IS INDEXED
000070            RECORD KEY IS 商品番号 OF 果物レコード
000080            ACCESS MODE IS SEQUENTIAL.

SIT COBOLは、OPEN文の実行時、ASSIGN TOの直後に書かれた定数と同じ名前の環境変数が存在するか確認し、存在する場合にはその環境変数からファイルを実体を取得し存在しない場合は、書かれた定数の値がファイルの実体であるとみなす。

さらには、次のようにデータ名で指定することも可能である。例えば、ファイルパスというデータ名でファイルの実体を指定するのであれば、次のように指定する。

000050     SELECT 果物ファイル ASSIGN TO ファイルパス
000060            ORGANIZATION IS INDEXED
000070            RECORD KEY IS 商品番号 OF 果物レコード
000080            ACCESS MODE IS SEQUENTIAL.
  :
000000 WORKING-STORAGE SECTION.
000000 01 ファイルパス PIC X(255).
  :
000000     MOVE "./果物ファイル.sqlite3" TO ファイルパス.
000000     OPEN OUTPUT 果物ファイル.
  :

SIT COBOLは、OPEN文の実行時、ASSIGN TOの直後に書かれたデータ名’ファイルパス’の値をファイルの実体であるとみなす。

(2) ファイルのレコード構造の定義

一方、ファイルがどのようなレコード構造を持つかは、データ部(DATA部)の、ファイル節(FILE節)に記述する。

000090 DATA DIVISION.
000100 FILE SECTION.
000110 FD 果物ファイル.
000120 01 果物レコード.
000130    02 商品番号 PIC 9(3).
000140    02 名前     PIC N(10).
000150    02 数量     PIC 9(5).

FDの次にファイル名を記述し、その次にレコード構造を記述する。ここでは、’商品番号’、’名前’、’数量’というデータ名を持つ’果物レコード’が定義されている。果物レコードの大きさは、外部10進数3文字(3バイト)と日本語10文字と英数字5文字(5バイト)を足し合わせた大きさである。

そして、商品番号が、主レコードキーである。商品である果物には果物を識別する商品番号がついているという想定である。当然のことながら、同じ番号の商品があることはなく、商品番号は重複不可である。

(注意) SIT COBOLは、ファイル中のレコードには、用途がDISPLAYである英数字項目、英数字編集項目、外部十進項目、数字編集項目、日本語項目、日本語編集項目のみしか定義できないようにしている。これは、COBOLを学習するにあたり、ファイルの中身をエディタ等で開いて確認できるようにすることに優先順位をおいているためである。

(3) ファイルのオープン

ファイルを開くには、OPEN文を使用する。

000410*    ファイルのオープン
000420     OPEN OUTPUT 果物ファイル.

オープンモードは、OPEN文の直後に記述する。この場合は、OUTPUTモードなので、ファイルが存在すれば上書きをし、存在しなければ1から作成することを指示している。

(4) データの出力

ファイルにデータを書き込むには、WRITE文を使用する。
下記は、果物テーブル(1)~果物テーブル(5)までのデータを順次果物レコードに転記し、WRITE文でレコードの内容をファイルに出力している。

000430*    5つの果物データをファイルに書き出し
000440     PERFORM VARYING I FROM 1 BY 1 UNTIL I > 5
000450         MOVE 果物テーブル(I) TO 果物レコード
000460         WRITE 果物レコード
000470     END-PERFORM.

MOVE文とWRITE文は次のようにFROM指定を使用して1文にすることもできる。

000460         WRITE 果物レコード FROM 果物テーブル(I)

ここで、1つ注意が必要なのは、索引ファイルは、順呼出し(ACCESS MODE SEQUENTIAL)の場合は、主キーの昇順にデータを 書き出さなければならない点である。ここでは、主キーである商品番号の値は、‘101’, ‘102’, … , ’105’と昇順になっており、WRITE文は成功する。

(5) ファイルのクローズ

ファイルを閉じるには、CLOSE文を使用する。

000480*    ファイルのクローズ
000490     CLOSE 果物ファイル.

(6) 実行結果

上記のプログラムを実行すると次のようなファイルが作成される。
SQLITE3.exeコマンドで索引ファイル(実際にはSQLITE3データベース)の中身を確認している。(“□”は日本語の空白を示す)

>sqlite3.exe 果物ファイル.sqlite3
sqlite> select * from records;
101|101リンゴ□□□□□□□00010
102|102オレンジ□□□□□00005
103|103メロン□□□□□□□00020
104|104バナナ□□□□□□□00008
105|105イチゴ□□□□□□□00012
sqlite>

なお、SIT COBOLは、OUTPUT指定のOPEN文において、索引ファイルを、次のような規則で作成する。

データベース名 ASSGIN TOに指定されたファイル名(“果物ファイル.sqlite3”)
テーブル名 “records”(固定)
主キー値を格納するカラム名 “KEY”(固定)
レコード内容を格納する領域のカラム名 “DATA”(固定)

8.4.3 索引ファイル例(2)

次に、索引ファイルのレコードを書き換えたり削除したりする例を見ていく。
参照するファイルは、例(1)で作成した”果物ファイル.sqlite3”である。

以下のプログラムは、オレンジ(商品番号102)の数量を15に変更し、またバナナレコード(商品番号104)を削除するプログラムである。

(サンプルプログラム名:索引ファイルの更新例.cob)

000000 IDENTIFICATION DIVISION.
000010 PROGRAM-ID. INDFILE002.
000020 ENVIRONMENT DIVISION.
000030 INPUT-OUTPUT SECTION.
000040 FILE-CONTROL.
000050     SELECT 果物ファイル ASSIGN TO "./果物ファイル.sqlite3"
000060            ORGANIZATION IS INDEXED
000070            RECORD KEY IS 商品番号 OF 果物レコード
000080            ACCESS MODE IS DYNAMIC.
000090 DATA DIVISION.
000100 FILE SECTION.
000110 FD 果物ファイル.
000120 01 果物レコード.
000130    02 商品番号 PIC 9(3).
000140    02 名前     PIC N(10).
000150    02 数量     PIC 9(5).
000160 PROCEDURE DIVISION.
000170 MAIN00.
000180*    ファイルのオープン
000190     OPEN I-O 果物ファイル.
000200*    主キー(商品番号)に102を設定してオレンジレコードを読む
000210     MOVE 102 TO 商品番号 OF 果物レコード.
000220     READ 果物ファイル
000230     INVALID
000240        DISPLAY "READ: オレンジレコードが見つからない"
000250        STOP RUN
000260     END-READ.
000270*    数量を15にして更新する。
000280     MOVE 15 TO 数量 OF 果物レコード.
000290     REWRITE 果物レコード
000300     INVALID
000310        DISPLAY "REWRITE: オレンジレコードの更新に失敗"
000320        STOP RUN
000330     END-REWRITE.
000340*    主キー(商品番号)に104を設定してバナナレコードを読む
000350     MOVE 104 TO 商品番号 OF 果物レコード.
000360     DELETE 果物ファイル
000370     INVALID
000380        DISPLAY "DELETE: バナナレコードの削除に失敗"
000390        STOP RUN
000400     END-DELETE.
000410*    ファイルのクローズ
000420     CLOSE 果物ファイル.
000430     STOP RUN.

(1) ファイルの定義

例(1)においては索引ファイルのアクセスモードは、順呼出し(SEQUENTIAL)としたが、キー指定でアクセスできるように、動的呼出し(DYNAMIC)とした。

000020 ENVIRONMENT DIVISION.
000030 INPUT-OUTPUT SECTION.
000040 FILE-CONTROL.
000050     SELECT 果物ファイル ASSIGN TO "./果物ファイル.sqlite3"
000060            ORGANIZATION IS INDEXED
000070            RECORD KEY IS 商品番号 OF 果物レコード
000080            ACCESS MODE IS DYNAMIC.

なお、キー指定アクセスのみであれば、アクセスモードは、乱呼出し(RANDOM)でもよいが、動的呼出しにしておくと、順呼出し、乱呼出しの両方が可能となるので、このプログラム例では動的呼出しにしている。

(2) データの入力および更新

データの入力を行うには、まず主キーである商品番号に値を設定し、それからREAD文を実行する。
以下の例では、商品番号に、オレンジの商品番号である102を設定して、READ文で果物ファイルを読んでいる。
000230行のINVALID指定は、INVALID条件(指定したキーの値を持つレコードが存在しない)が発生したときの処理を書いている。ここでは、DISPLAY文を実行後、プログラムを終了させている。

000200*    主キー(商品番号)に102を設定してオレンジレコードを読む
000210     MOVE 102 TO 商品番号 OF 果物レコード.
000220     READ 果物ファイル
000230     INVALID
000240        DISPLAY "READ: オレンジレコードが見つからない"
000250        STOP RUN
000260     END-READ.

READ文が成功すると、果物レコードには、オレンジのデータが読み込まれているので、数量を15に変更して、REWRITE文を実行する。

000270*    数量を15にして更新する。
000280     MOVE 15 TO 数量 OF 果物レコード.
000290     REWRITE 果物レコード
000300     INVALID
000310        DISPLAY "REWRITE: オレンジレコードの更新に失敗"
000320        STOP RUN
000330     END-REWRITE.

000300行のINVALID指定は、READ文と同じく、INVALID条件が発生したときの処理を書いている。ここでは、DISPLAY文を実行後、プログラムを終了させている。

なお、上記の更新の流れは、READ文でレコードを読み、そのレコードをREWRITE文で更新という流れとしたが、動的呼出し(DYANMIC)の場合は、READ文を実行せずとも、ただちにREWRITE文を実行できる。したがって、レコードの一部の更新だけではなく、ほぼ全体を更新するような場合はREWRITE文のみを使ったほうが効率的である。

(3) データの削除

データの削除を行う場合は、キーに削除したいレコードの値を指定してDELETE文を実行する。
下記の例では、バナナレコードを削除するので、主キーである商品番号に104を設定してDELETE文を実行している。

000340*    主キー(商品番号)に104を設定してバナナレコードを読む
000350     MOVE 104 TO 商品番号 OF 果物レコード.
000360     DELETE 果物ファイル
000370     INVALID
000380        DISPLAY "DELETE: バナナレコードの削除に失敗"
000390        STOP RUN
000400     END-DELETE.

000370行のINALID指定については、READ文、REWRITE文で説明したとおり、指定したキーが存在しない場合の処理を書いている。

(4) 実行結果

上記のプログラムを実行すると’果物ファイル.sqlite3’の中身は次のようになる。

sqlite> select * from records;
101|101リンゴ□□□□□□□00010
102|102オレンジ□□□□□00015
103|103メロン□□□□□□□00020
105|105イチゴ□□□□□□□00012
sqlite>

オレンジの数量が15に変わっており、またバナナレコードが削除されているのがわかる。

8.4.4 索引ファイル例(3)

索引ファイルを動的呼出しで開くと、特定のキー値以上のデータだけを読み出すことができる。
例えば、’果物ファイル.sqlite3’の、商品番号が103以上のレコードをすべて読み出すというプログラムは次のようになる。

(サンプルプログラム名:索引ファイルの更新例2.cob)

000000 IDENTIFICATION DIVISION.
000010 PROGRAM-ID. INDFILE003.
000020 ENVIRONMENT DIVISION.
000030 INPUT-OUTPUT SECTION.
000040 FILE-CONTROL.
000050     SELECT 果物ファイル ASSIGN TO "./果物ファイル.sqlite3"
000060            ORGANIZATION IS INDEXED
000070            RECORD KEY IS 商品番号 OF 果物レコード
000080            ACCESS MODE IS DYNAMIC.
000090 DATA DIVISION.
000100 FILE SECTION.
000110 FD 果物ファイル.
000120 01 果物レコード.
000130    02 商品番号 PIC X(3).
000140    02 名前     PIC N(10).
000150    02 数量     PIC 9(5).
000160 PROCEDURE DIVISION.
000170 MAIN00.
000180*    ファイルのオープン
000190     OPEN I-O 果物ファイル.
000200*    主キー(商品番号)に103を指定してSTART文を実行する
000210     MOVE 103 TO 商品番号 OF 果物ファイル.
000220     START 果物ファイル
000230     INVALID
000240        DISPLAY "START: レコードが見つからない"
000250        STOP RUN
000260     END-START.
000270     PERFORM FOREVER
000280        READ 果物ファイル NEXT
000290        AT END
000300           EXIT PERFORM
000310        END-READ
000320        DISPLAY 果物レコード
000330     END-PERFORM.
000340*    ファイルのクローズ
000350     CLOSE 果物ファイル.
000360     STOP RUN.

(1) ファイルのオープン

今回は、更新を伴なわない例であるが、ひとまず、I-Oモードで開いておく。

000180*    ファイルのオープン
000190     OPEN I-O 果物ファイル.

(2) 読み出すレコードの指定

主キーのある特定の値以上のレコードを順次読み出しするには、START文を使用する。
このプログラムでは、次のように主キーである商品番号に103を指定してSTART文を実行している。

000200*    主キー(商品番号)に103を指定してSTART文を実行する
000210     MOVE 103 TO 商品番号 OF 果物ファイル.
000220     START 果物ファイル
000230     INVALID
000240        DISPLAY "START: レコードが見つからない"
000250        STOP RUN
000260     END-START.

このSTART文を実行してから READ NEXT文を実行すると、最初に103の主キーを持つレコードが読み出される。

しかし、主キーに103を持つレコードが存在しない場合は、INVALID条件が発生し、000230行目から始まるDISPLAY文とSTOP文が実行される。

実は、上記のSTART文は次のような書き方と同じである。

000210     MOVE 103 TO 商品番号 OF 果物ファイル.
000220     START 果物ファイル KEY = 商品番号 OF 果物ファイル

そして、指定したキーを持つレコードが存在しなくとも、それ以上の値を持つレコードが存在した場合は、INVALID条件としないようにもできる。それは、次のようにキー指定に”>=“を書く。

000210     MOVE 104 TO 商品番号 OF 果物ファイル.
000220     START 果物ファイル KEY >= 商品番号 OF 果物ファイル

商品番号104はバナナレコードであるが、例(2)にて削除しているため、現時点でレコードは存在しない。しかし、商品番号105を持つイチゴレコードが存在するので、このSTART文はINVALID条件は発生せず成功する。そして、次に実行するREAD NEXT文では、商品番号105のイチゴレコードが読み込まれる。

なお、「KEY > 商品番号 OF 果物ファイル」と書くと、今設定されている商品番号よりも大きい商品番号を持つレコードに位置づく。

(3) 指定したレコードの読み込み

START文で位置づけたレコードの読み込みは、READ NEXT文によって行う。
このプログラムでは、FOREVER指定のPERFORMで、EOFとなるまでREAD NEXTを実行している。

000270     PERFORM FOREVER
000280        READ 果物ファイル NEXT
000290        AT END
000300           EXIT PERFORM
000310        END-READ
000320        DISPLAY 果物レコード
000330     END-PERFORM.

ここで、“NEXT”は必須であることに注意されたい。もし、NEXTを省略した場合には、START命令で位置づいたレコードではなく、新たに主キーの値を持つレコードを読込むという指定となるからである。

(4) 実行結果

上記のプログラムを実行すると、00320行目のDISPLAY文により下記が出力される。(“□”は日本語の空白を示す)

103メロン□□□□□□□□□□00020
105イチゴ□□□□□□□□□□00012

START文によって、最初に商品番号が103を持つレコードに位置づけられ、その後、READ NEXT文によって、103および105のレコードが読込まれたことがわかる。

8.5 ファイル関連の文法まとめ

ここでは、早見表として、ファイル関連の文法についてまとめておく。

8.5.1 SELECT句

SELECT句は、ファイル形式の定義を行う。環境部(ENVIRONMENT部)の入出力節(INPUT-OUTPUT節)のファイル管理段落(FILE-CONTROL段落)に記述する。

順ファイル
SELECT ファイル名-1 ASSIGN TO { 定数-1 | 一意名-1 }
    [[ORGANIZATION IS] SEQUENTIAL]
    [ACCESS MODE IS SEQUENTIAL]
    [FILE STATUS IS 一意名-2].
索引ファイル
SELECT ファイル名-1 ASSIGN TO { 定数-1 | 一意名-1 }
    [ORGANIZATION IS] INDEXED
    ACCESS MODE IS {SEQUENTIAL | RANDOM | DYNAMIC}
    RECORD KEY IS データ名-1
    [ALTERNATE RECORD KEY IS {データ名-2} ... ]
    [FILE STATUS IS 一意名-2].

8.5.2 FD句

FD句は、ファイルのデータ構造の定義であり、データ部(DATA部)のファイル節(FILE節)に指定する。

FD ファイル名-1.
{ レベル番号 データ定義 } ...

8.5.3 CLOSE文

CLOSE文は、ファイルを閉じる

CLOSE {ファイル名-1} ...

8.5.4 DELETE文

DELETE文はレコードを削除する。

順呼出し
DELETE ファイル名-1
乱呼出し/動的呼出
DELETE ファイル名-1
[INVALID 無条件文-1]
[NOT INVALID 無条件文-2]
[END-DELETE]

8.5.5 OPEN文

ファイルを開く

OPEN {{INPUT | OUTPUT | I-O | EXETND} ファイル名-1 ...} ...

8.5.6 READ文

ファイルからレコードを読み込む

順呼出し/動的呼出し
READ ファイル名-1 [NEXT] [INTO 一意名-1]
[AT END 無条件文-1]
[NOT AT END 無条件文-2]
[END-READ]
乱呼出し/動的呼出し
READ ファイル名-1 [INTO 一意名-1]
[KEY IS データ名-1]
[INVALID 無条件文-1]
[NOT INVALID 無条件文-2]
[END-READ]

8.5.7 REWRITE文

レコードを更新する。

順呼出し
REWRITE レコード名-1 [FROM 一意名-1]
[END-REWRITE]
乱呼出し/動的呼出し
REWRITE レコード名-1 [FROM 一意名-1]
[INVALID 無条件文-1]
[NOT INVALID 無条件文-1]
[END-REWRITE]

8.5.8 START文

指定したキーを持つレコードに位置づける

START ファイル名
[KEY {= | > | >=} データ名-1]
[INVALID 無条件文-1]
[NOT INVALID 無条件文-2]
[END-START]

8.5.9 WRITE文

レコードを書き出す

順呼出し
WRITE レコード名-1 [FROM 一意名-1]
[END-WRITE]
乱呼出し/動的呼出し
WRITE レコード名-1 [FROM 一意名-1]
[INVALID 無条件文-1]
[NOT INVALID 無条件文-2]
[END-WRITE]

8.5.10 USE文

ファイルの入出力状態が成功以外のときに実行される手続きを宣言する。

USE AFTER STANDARD {EXCEPTION | ERROR} PROCEDURE ON 
    { {ファイル名-1}... | INPUT | OUTPUT | I-O | EXTEND}