# OpenVMS
ユーザーズ・マニュアル

前へ | 次へ | 目次 | 索引

# 16.10 ファイルへの書き込み

ファイルにデータを書き込むには，次のようにします。

手順 | 操作
--- | ---
1 | 書き込み用のファイルをオープンする。
2 | 書き込みループの先頭にラベルを付ける。 単独のレコードを書き込んだり読み込んだりする場合を除いて，ファイル入出力は常にループの中で実行される。
3 | 書き込もうとするデータを読み込む。 INQUIRE コマンドまたは READ コマンドを使用して，データをシンボルに読み込む。
4 | データをテストする。 データが入ってるシンボルをチェックする。シンボルが空の場合 (たとえば，Return を押して当該行にデータを入力しない場合) には，ファイルに書き込もうとするデータの終わりに達したら，ループの終わりに進む。それ以外の場合には，処理を続ける。
5 | データをファイルへ書き込む。 WRITE コマンドを使用して，シンボルの値 (1 つのレコード) をファイルに書き込む。
6 | ループの先頭に戻る。 以下，ファイルに書き込むデータがなくなるまで，ループが繰り返される。
7 | ループを終了して，ファイルをクローズする。

次のコマンド・プロシージャは，データを新しいファイル STATS.DAT に書き込みます。この名前のファイルが存在する場合には，新しいバージョンが作成されます。

    $ ! Write a file
    $ ON ERROR THEN EXIT                         ! Exit if the command
    $ !                                          !   procedure cannot
    $ !                                          !   open the file
    $ OPEN/WRITE IN_FILE DISK4:[MURPHY]STATS.DAT ! Open the file
    $ ON CONTROL_Y THEN GOTO END_WRITE           ! Close the file if you
    $ !                                          !   quit execution with
    $ !                                          !   Ctrl/Y
    $ ON ERROR THEN GOTO END_WRITE               ! Close the file if an
    $ !                                          !   error occurs
    $WRITE:                                      ! Begin the loop
    $ INQUIRE STUFF "Input data"                 ! Prompt for input
    $ IF STUFF .EQS. "" THEN GOTO END_WRITE      ! Test for the end of
    $ !                                          !   the file
    $ WRITE IN_FILE STUFF                        ! Write to the file
    $ GOTO WRITE                                 ! Go to the beginning
    $END_WRITE:                                  ! End the loop
    $ !                                          !
    $ CLOSE IN_FILE                              ! Close the file

## 16.10.1 固有の名前を持つファイルの作成

固有の名前を持つファイルを作成するには，F$SEARCH レキシカル関数を使用して，その名前がすでにディレクトリに存在するかどうかを調べます。 F$SEARCH についての詳細は，『Compaq OpenVMS DCL ディクショナリ』のレキシカル関数の説明を参照してください。

次のコマンド・プロシージャは，ファイル名を求めるプロンプトを出してから， F$SEARCH レキシカル関数を使用して，省略時のディレクトリで指定された名前を検索します。指定された名前を持つファイルがすでに存在する場合には，ERROR_1 に制御が渡され，プロシージャは，"The file already exists" のメッセージを表示してから， GET_NAME ラベルに制御を戻します。このとき，別のファイル名を求めるプロンプトを出します。

    $ ! FILES.COM
    $ !
    $GET_NAME:
    $ INQUIRE FILE "File"           ! Prompt the user for a file name
    $ IF F$SEARCH (FILE) .NES. ""   ! Make sure the file name is unique
    $ THEN
    $    WRITE SYS$OUTPUT "The file already exists"
    $    GOTO GET_NAME
    $ ELSE
    $    OPEN/WRITE IN_FILE 'FILE'  ! Open the file with WRITE access
    $ ENDIF
       .
       .
       .
    $ EXIT

# 16.11 WRITE コマンドの使用

これ以降の節では，WRITE コマンドの使用について説明します。

## 16.11.1 データの指定

WRITE コマンドのデータを指定する場合は， 第 14 章 に説明する文字列式の規則に従います。次に，いくつかのデータの指定方法を示します。

- 文字列式として書き込むデータを指定する。 WRITE コマンドは，シンボルとレキシカル関数を自動的に置換する。

- リテラル文字列として文字列を出力ファイルに書き込む。 WRITE コマンドは，引用符で囲まれた文字列に対してシンボル置換を実行しない。

- リテラル文字列とシンボル名を組み合わせる。シンボル置換を強制的に実行するには，文字列全体を引用符で囲み，シンボルの前に 2 つの一重引用符，シンボルの後に 1 つの一重引用符を指定する。
  リテラル文字列とシンボル名を組み合わせて使用する別の方法として，シンボルの前後にカンマを挿入し，カンマで区切られたシンボルの前後を引用符で囲み，文字列全体を二重引用符で囲む方法がある。次の例を参照。

      $ WRITE OUTFILE "Count is ",COUNT,"."

- 強制的なシンボル置換を実行するには，WRITE コマンド行に一重引用符を指定する。

- 一重引用符を使用して文字列内で強制的なシンボル置換を実行することにより，リテラル文字列とレキシカル関数を組み合わせる。

例

    $! Define symbols
    $!
    $ CREATED = "File created April 15, 1996"
    $ COUNT = 4
    $ P4 = "fourth parameter"
    $!
    $! Open the file DATA.OUT for writing
    $!
    $ OPEN/WRITE OUTFILE DISK4:[MURPHY]DATA.OUT
    $!
    $ WRITE OUTFILE CREATED                 (1)
    $ WRITE OUTFILE "CREATED"               (2)
    $!
    $ WRITE OUTFILE "Count is ''COUNT'."    (3)
    $ WRITE OUTFILE P'COUNT'                (4)
    $!
    $ WRITE OUTFILE "Mode is ''f$mode()'"   (5)
    $!
    $ CLOSE OUTFILE

    $ TYPE DISK4:[MURPHY]DATA.OUT [Return]   (6)
    File created April 15, 1996
    CREATED
    Count is 4.
    fourth parameter
    Mode is INTERACTIVE
    $

例を確認する際には，次のことに注意してください。

1. 書き込むデータを文字列式として指定する。

2. CREATED 文字列をリテラル文字列として出力ファイルに書き込む。

3. リテラル文字列とシンボル名を組み合わせる。

4. WRITE コマンドの中で一重引用符を使用してシンボル置換を強制する。この例では，WRITE コマンドは，値を COUNT シンボルに置換し，その結果のコマンド文字列 (P4) でシンボル置換を行う。

5. 一重引用符を使用してリテラル文字列とレキシカル関数を組み合わせる。

6. 前の WRITE コマンドによって出力ファイル DATA.OUT に書き込まれたデータを表示する。

## 16.11.2 /SYMBOL 修飾子の使用

WRITE コマンドは，レコードを書き込むとき，書き込まれたレコードの後にレコード・ポインタを置きます。 WRITE コマンドは，長さが最大 2,048 バイトまでのレコードを書き込めます。

次のいずれかの条件が存在するときには，/SYMBOL 修飾子を使用してレコードを書き込みます。

- レコードが 1,024 バイトより長い。

- WRITE コマンドの中の式が 255 バイトより長い。

長いレコードの書き込みについての詳細は，『Compaq OpenVMS DCL ディクショナリ』の WRITE コマンドの説明を参照してください。

## 16.11.3 /UPDATE 修飾子の使用

WRITE コマンドと一緒に /UPDATE 修飾子を使用すれば，新しいレコードを挿入せずに，レコードを変更できます。 /UPDATE 修飾子を使用するには，読み込みと書き込み両用でファイルをオープンしなければなりません。

# 16.12 READ コマンドの使用

READ コマンドは，レコードを読み込み，その内容にシンボルを割り当てます。 READ コマンドを使用すると， 1,024 文字以内の長さのレコードを読み込むことができます。ファイルからデータを読み込むには，次のようにします。

手順 | 操作
--- | ---
1 | 読み込み用のファイルをオープンする。
2 | 読み込みループの先頭にラベルを付ける。 単独のレコードを読み込んだり書き込んだりする場合を除いて，ファイル入出力は常にループの中で行われる。
3 | ファイルからデータを読み込む。 READ コマンドと一緒に /EDN_OF_FILE修飾子を使用して，レコードを読み込み，その内容をシンボルに割り当てる。 /END_OF_FILE 修飾子を使用すると，ファイル終わりへの到達時点で， /END_OF_FILE 修飾子によって指定されたラベルに制御が渡される。普通は，読み込みループの終わりを示すラベルを指定する。
4 | データを処理する。 ファイルを順に読み込む場合には，現在のレコードを処理してから次のレコードを読み込む。
5 | ループの始めに戻る。 ファイル終わりに到達するまで，ループが繰り返される。
6 | ループを終了して，ファイルをクローズする。

次のコマンド・プロシージャは， STATS.DAT ファイルの中のそれぞれのレコードを読み込んで処理します。ファイルの終端状態が戻るまで，READ コマンドを繰り返し実行します。ファイルの終端状態が戻ると，END_READ のラベルが付いた行に分岐します。

    $ OPEN/READ INFILE DISK4:[MURPHY]STATS.DAT  !Open the file
    $ !
    $READ_DATA:                                 !Begin the loop
    $ READ/END_OF_FILE=END_READ INFILE RECORD   !Read a record; test for
    $                                           !  end of file
    $                                           ! Process the data
       .
       .
       .
    $ GOTO READ_DATA                            !Go to the beginning
    $                                           !   of the loop
    $END_READ:                                  !End of loop
    $ CLOSE INFILE                              !Close the file
    $ EXIT

READ コマンドのシンボル名を指定すると，コマンド・インタプリタは，現在のコマンド・レベルのローカル・シンボル・テーブルにシンボル名を置きます。 2 つ以上の READ コマンドに同じシンボル名を使用すると，それぞれの READ コマンドがシンボル名の値を再定義します。たとえば，上例のプロシージャでは，READ コマンドは，ループを通るたびに入力ファイル (STATS.DAT) から新しいレコードを読み込み，このレコードを使用して RECORD シンボルの値を再定義します。

## 16.12.1 /END_OF_FILE 修飾子の使用

ファイルから読み込みを行う場合，普通は，ファイルの終端に到達するまで1つ1つのレコードを順に読み込んで処理していきます。 READ コマンドと一緒に /END_OF_FILE 修飾子を使用すれば，ループが作成され，ファイルからレコードを読み込んで処理し，すべてのレコードを読み込み終わった時点でループを終了することができます。

/END_OF_FILE 修飾子に指定するラベルは，GOTO コマンドに指定するラベルと同じ規則に従うことに注意してください (GOTO コマンドについての詳細は， 第 15 章 を参照してください)。

ループの中で READ コマンドを使用するときには，必ず /END_OF_FILE修飾子を使用するようにします。そうしないと，OpenVMS レコード管理サービス (OpenVMS RMS) によってファイルの終端を示すエラー状態が戻されたときに，コマンド・インタプリタは，現在のON コマンドに指定されるエラー・アクションを実行します。たとえば，OpenVMS RMS がエラー状態 %RMS-E-EOF を戻すと，コマンド・プロシージャが固有のエラー処理方法を設定している場合を除いて，コマンド・プロシージャは終了します。

## 16.12.2 /INDEX と /KEY 修飾子の使用

索引順編成ファイルからレコードをランダムに読み込むには， READ コマンド修飾子の /INDEX と /KEY を使用します。 /INDEX と /KEY 修飾子は，索引の中で指定されたキーを探してそのキーに関連するレコードを戻すことによって，レコードをファイルから読み込むように指定します。索引を指定しないと，主インデックス (0) が使用されます。

レコードをランダムに読み込む場合， /KEY または /INDEX 修飾子を指定せずに READ コマンドを使用すると，ファイルの残りの部分を順に読み込むことができます。

## 16.12.3 /DELETE 修飾子の使用

READ コマンドと一緒に /DELETE 修飾子を使用すると，索引順編成ファイルからレコードを削除できます。 /DELETE 修飾子を指定した場合は，レコードの読み込みが終わってからレコードがファイルから削除されます。 /DELETE 修飾子と一緒に /INDEX と /KEY 修飾子を使用すれば，特定のキーによって指定されたレコードを削除できます。

/DELETE，/INDEX，/KEY 修飾子についての詳細は，『Compaq OpenVMS DCL ディクショナリ』の READ コマンドの説明を参照してください。

# 16.13 CLOSE コマンドの使用

CLOSE コマンドは，ファイルを閉じ， OPEN コマンドで作成された論理名の割り当てを解除します。コマンド・プロシージャを終了する場合には，その前にコマンド・プロシージャで開いたすべてのファイルを閉じてください。開いたファイルを閉じなかった場合には，コマンド・プロシージャが終了するときに，ファイルは開かれたままになり，開かれているファイルに割り当てられている論理名は，プロセス論理名テーブルから削除されません。

次の例では，CLOSE コマンドはファイル STATS.DAT を閉じ，論理名 INFILE の割り当てを解除します。

    $ OPEN INFILE DISK4:[MURPHY]STATS.DAT
       .
       .
       .
    $ CLOSE INFILE

# 16.14 ファイルの変更

この節では，次の 3 種類のファイル変更方法について説明します。

- レコードの更新

- 新しい出力ファイルの作成

- レコードの追加

## 16.14.1 レコードの更新

更新方式を使用してレコードを変更する場合には，ファイル内の一部のレコードだけを変更できます。この方式では，レコードのサイズを変更したり，ファイル内のレコード数を変更することができないため，書式化されたレコード (たとえばデータ・ファイル内のレコード) に対してだけ使用できます。

ファイルの一部だけを変更するには，次の操作を実行します。

手順 | 操作
--- | ---
1 | 読み込みアクセスと書き込みアクセスの両用ファイルをオープンする。
2 | READ コマンドを使用して，変更したいレコードに到達するまでファイルを読み込む。
3 | レコードを変更する。 順編成ファイルでは，このレコードのテキストは元のレコードと同じサイズでなければならない。変更済みのレコードのテキストの方が短い場合は，レコードにスペースを埋め込んで，元のレコードと同じ長さになるまで変更済みのレコードの終わりにスペースを追加する。変更済みレコードのテキストの方が長い場合は，新しいファイルを作成する必要がある。
4 | WRITE/UPDATE コマンドを使用して変更したレコードをファイルに書き込む。
5 | 変更しようとするすべてのレコードの変更が終わるまで，手順 2 〜 4 を繰り返す。
6 | CLOSE コマンドを使用してファイルをクローズする。 ファイルをクローズした後，個々のレコードが変更済みであっても，ファイルのバージョン番号は最初と同じである。

次のコマンド・プロシージャは，それぞれのレコードを読み込んで更新することによって，順編成ファイルに変更を加える方法を示しています。

    $! Open STATS.DAT and assign it the logical name FILE
    $!
    $ OPEN/READ/WRITE FILE DISK4:[MURPHY]STATS.DAT
    $ BEGIN_LOOP:
    $! Read the next record from FILE into the symbol RECORD
    $     READ/END_OF_FILE=END_LOOP FILE RECORD
    $! Display the record and see if the user wants to change it
    $! If yes, get the new record.  If no, repeat loop
    $!
    $     PROMPT:
    $          WRITE SYS$OUTPUT RECORD
    $          INQUIRE/NOPUNCTUATION OK "Change? Y or N [Y] "
    $          IF OK .EQS. "N" THEN GOTO BEGIN_LOOP
    $          INQUIRE NEW_RECORD "New record"
    $! Compare the old and new records
    $! If old record is shorter than new record, issue an
    $! error message. If old record and new record are the
    $! same length, write the record. Otherwise pad the new
    $! record with spaces so it is correct length
    $!
    $          OLD_LEN = F$LENGTH(RECORD)
    $          NEW_LEN = F$LENGTH(NEW_RECORD)
    $          IF OLD_LEN .LT. NEW_LEN THEN GOTO ERROR
    $          IF OLD_LEN .EQ. NEW_LEN THEN GOTO WRITE_RECORD
    $          SPACES = "             "
    $          PAD = F$EXTRACT(0,OLD_LEN-NEW_LEN,SPACES)
    $          NEW_RECORD = NEW_RECORD + PAD
    $!
    $     WRITE_RECORD:
    $          WRITE/UPDATE FILE NEW_RECORD
    $          GOTO BEGIN_LOOP
    $!
    $     ERROR:
    $          WRITE SYS$OUTPUT "Error -- New record is too long"
    $          GOTO PROMPT
    $!
    $     END_LOOP:
    $          CLOSE FILE
    $          EXIT

レコードはターミナルに表示され，レコードを変更する必要があるかどうかが尋ねられます。レコードの変更を選択すると，ターミナルから新しいレコードが読み込まれ，新しいレコードの長さと元のレコードの長さとが比較されます。元のレコードの方が長い場合には，新しいレコードにスペースを追加して同じ長さにします。元のレコードの方が短い場合には，エラー・メッセージが表示され，新しいレコードを求めるプロンプトがもう一度出されます。

## 16.14.2 新しい出力ファイルの作成

ファイルに大きな変更を加えるには，そのファイルを読み込みアクセス用にオープンし，新しいファイルを書き込みアクセス用にオープンします。新しい出力ファイルを作成するので，レコードのサイズを変更したり，レコードを追加したり削除したりできます。

OPEN/WRITE コマンドは，書き込みアクセス用の新しいファイルをオープンします。新しいファイルは元のファイルと同じ名前にすることができ，バージョン番号は，古いファイルのバージョン番号より 1 だけ大きくなります。

注意 読み込み用に正しいファイルがオープンされるように，既存のファイルを読み込みアクセス用にオープンしてから，新しいバージョンを書き込みアクセス用にオープンするようにしなければなりません。

ファイルに変更を加えるには，次の手順に従ってください。

手順 | 操作
--- | ---
1 | 該当ファイルを読み込みアクセス用にオープンする。 これは入力ファイルであり，このファイルを変更する。
2 | 書き込みアクセス用に新しいファイルをオープンする。 これは出力ファイルであり，このファイルを作成する。出力ファイルに入力ファイルと同じ名前を指定すると，出力ファイルは，入力ファイルより1 だけ大きいバージョン番号を持つ。
3 | READ コマンドを使用して，変更中のファイルからレコードを 1 つずつ読み込む。 元のファイルからそれぞれのレコードを読み込むときに，レコードをどのように処理するかを決定する。
4 | すべてのレコードが終了するまで，レコードの読み込みと処理を続ける。
5 | CLOSE コマンドを使用して，入力ファイルと出力ファイルの両方をクローズする。

次の表では，RECORD シンボルに元のファイルから読み込んだレコードが収められます。

場合 | 結果
--- | ---
レコードに変更なし | 新しいファイルに同じシンボルを書き込む。
レコードに変更あり | INQUIRE コマンドを使用して別のレコードをシンボルに読み込んでから，変更済みのシンボルを新しいファイルに書き込む。
レコードが削除されている | シンボルを新しいファイルに書き込まない。
レコードが挿入されている | ループを使用して，シンボルにレコードを読み込んだり，シンボルを新しいファイルに書き込んだりする。

- 次の例では，NEW_FILE シンボルが新しいファイルに書き込まれています。

      $ ! No change
      $ WRITE NEW_FILE RECORD

- 次の例では，INQUIRE コマンドが変更されたシンボルを新しいファイルに書き込むために使用されています。

      $ ! Change
      $ INQUIRE NEW_RECORD "New record"
      $ WRITE NEW_FILE NEW_RECORD

- 次の例では，ループが新しいファイルにシンボルを書き込むために使用されています。

      $ ! Insertion
      $LOOP:
      $ !Get new records to insert
      $ INQUIRE NEW_RECORD "New record"
      $ IF RECORD .EQS. "" THEN GOTO END_LOOP
      $ WRITE NEW_FILE NEW_RECORD
      $ GOTO LOOP
      $END_LOOP:

例：出力ファイルの作成

次の例は，入力ファイルからレコードを読み込み，レコードを処理してから出力ファイルにコピーするコマンド・プロシージャを示しています。

    $! Open STATS.DAT for reading and assign it
    $! the logical name INFILE
    $! Open a new version of STATS.DAT for writing
    $! and assign it the logical name OUTFILE
    $!
    $ OPEN/READ INFILE DISK4:[MURPHY]STATS.DAT
    $ OPEN/WRITE OUTFILE DISK4:[MURPHY]STATS.DAT
    $!
    $ BEGIN_LOOP:
    $! Read the next record from INFILE into the symbol RECORD
    $!
    $     READ/END_OF_FILE=END_LOOP INFILE RECORD
    $! Display the record and see if the user wants to change it
    $! If yes, get the new record
    $! If no, write record directly to OUTFILE
    $!
    $     PROMPT:
    $          WRITE SYS$OUTPUT RECORD
    $          INQUIRE/NOPUNCTUATION OK "Change? Y or N [Y] "
    $          IF OK .EQS. "N" THEN GOTO WRITE_RECORD
    $          INQUIRE RECORD "New record"
    $!
    $     WRITE_RECORD:
    $          WRITE OUTFILE RECORD
    $          GOTO BEGIN_LOOP
    $!
    $! Close input and output files
    $     END_LOOP:
    $          CLOSE INFILE
    $          CLOSE OUTFILE
    $          EXIT

前へ | 次へ | 目次 | 索引