- ベストアンサー
COBOLでのランダムアクセス
- COBOL初心者が「mokuhyou.dat」というファイルにデータを格納するプログラムを作成しましたが、実行時にエラーが発生しています。
- エラーメッセージ「JMP0310I-U OPEN ERROR FILE=mokuhyou.dat. 'ACC-METHOD'. PGM=TEST046 ADR=00401258」が表示され、ファイルが正常に読み込めない可能性があります。
- 解決方法を教えてください。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
う~ん、惜しい。 SELECT URIAGE-MOKUHYOU ASSIGN TO "C:\DAT\MOKUHYOU.TXT" ORGANIZATION IS SEQUENTIAL. か、 SELECT URIAGE-MOKUHYOU ASSIGN TO "C:\DAT\MOKUHYOU.TXT" ORGANIZATION IS LINE SEQUENTIAL. にする(行順ファイルがサポートされてて使える場合) SELECT N-URIAGE-MOKUHYOU ASSIGN TO "C:\DAT\MOKUHYOU" ORGANIZATION IS INDEXED ACCESS MODE IS DYNAMIC RECORD KEY IS NUM-SHITEN-CODE. にする。索引ファイルを使う場合、主ファイル名は8文字以内に、拡張子は付けないのが無難。あと、ファイル名は大文字にしとく方が無難(後述) 05 UM-KINGAKU PIC 9(10) OCCURS 12. の後ろに 05 FILLER PIC X(2). が必要(改行コードのCRとLFの分) MOVE UM-REC TO NUM-REC はやっちゃいけない(テキスト側に改行コードのフィラが増え、テキストファイルと索引ファイルのレコード構造が違ってしまったから。それに各項目ごとに移送してるから不要) REWRITE NUM-REC は WRITE NUM-REC INVALID KEY REWRITE NUM-REC END-WRITE にする。OUTPUTオープンしてるからファイルは空になってる。つまりレコードは1つも存在しないからREWRITEは出来ない。 「WRITEしてみてINVALID KEYだったらREWRITE」をする理由は、元のテキストファイルに 0001SHITEN-A旧店名、AAに変更済~~~ 0001SHITEN-AA~~~~~~~~~~~~ 0002SHITEN-B~~~~~~~~~~~~ 0003SHITEN-C~~~~~~~~~~~~ のように「同一の支店コードが2つ書いてあった時」のため。REWRITEではなく「同一コードが2つある」とのエラー表示をして終了するのでも良い。 これでダメだとしたら 「使ってるCOBOLに方言があって、テキストファイルを扱う場合のSELECT文に、何か特殊な書き方をしなきゃならない」 か 「『c:\dat\』のように、ドライブやパス指定を書けない」 か 「索引ファイルのファイル名には『n-mokuhyou.dat』のように拡張子は付けちゃいけない」 か 「索引ファイルのファイル名は『n-mokuhyou』のように8文字を超えちゃいけない」 か 「ファイル名に英文字の小文字を含むと問答無用でエラー」 などの制約が存在する場合がある。 特に索引ファイルでの「拡張子は付けない」と「主ファイル名は8文字以内」は注意。これを守らないとCOBOLが内部でキーファイルのファイル名を自動生成する際に、生成に失敗して実行時にOPEN文で予期せぬエラーが出る可能性が。 古いMS-DOSの仕様を引きずってて廃止して欲しい制約なんだが…。 あと「古いMS-DOSの仕様」に関連してか、ファイル名は大文字を使うのが慣例になっている。ファイル名に小文字を使うと動かないCOBOLがあるらしいので。
その他の回答 (3)
- chie65536
- ベストアンサー率41% (2512/6032)
>(2)SELECT FILE01 ASSIGN TO INPUT-FL. >OPEN INPUT FILE01 >というコードについて、(1)は意味が分かるのですが、 >(2)はどこからどういうファイルをOPENするのですか? どこかに 01 INPUT-FL PIC X(80) VALUE "c:\dat\input-file.txt". の行がありませんか? それか、どこかに 01 INPUT-FL PIC X(80). の行があって、OPEN INPUT FILE01の前に MOVE "c:\dat\input-file.txt" TO INPUT-FL. って書いてませんか? 普通、SELECT文には、直接ファイル名は指定しないのです。 なぜなら、以下のような手法で、複数のファイルを切り替える事が多いからです。 MOVE "INPUT001" TO INPUT-FL. PERFORM MAIN-START THRU MAIN-EXIT. MOVE "INPUT002" TO INPUT-FL. PERFORM MAIN-START THRU MAIN-EXIT. MOVE "INPUT003" TO INPUT-FL. PERFORM MAIN-START THRU MAIN-EXIT. STOP RUN. * MAIN-START. OPEN INPUT FILE01. (メインの処理) CLOSE FILE01. MAIN-EXIT. EXIT. こうしておけば、OPEN前にINPUT-FLにファイル名を入れ直す事で、同じ処理で複数のファイルを繰り返して操作する事が出来ます。 また「オープンするファイル名は、起動時のコマンドラインに書いてある」と言うケースが多く、コマンドラインからファイル名をMOVEしてくる必要性から、ファイル名部分が変数になっているのが普通なのです。
お礼
なるほど!大変よく分かりました。 これで、一通りファイル操作の方法が理解できました。 順読みだとファイルの突合せ処理に無駄が多かったですが、索引ファイルだと効率も良いしコードもすっきりしますね! これから本格的にCOBOLを使った業務をしないといけないので、また何かあったら教えてください。 本当にありがとうございました。
- chie65536
- ベストアンサー率41% (2512/6032)
>基本的な質問で恐縮ですが、mokuhyou.datのファイルは自分がテストデータ >をエディタで編集し、mokuhyou.datの名前で保存しただけなのですが、 >そうではなく、mokuhyou.datは別プログラムから作成すべきということ >なのでしょうか? その通りです。 COBOLは以下の4種類のファイルを扱えます。 ・レコード順ファイル(テキストファイル) ・行順ファイル(テキストファイル。一部のCOBOLでのみサポート) ・相対ファイル(バイナリファイル) ・索引ファイル(バイナリファイル。データとキーの2つのファイルでセット) 質問者さんのように「特定の値(支店コード)をキーにして、キーで指定したレコードを読み込む場合」は「索引ファイル」を使用します。 この「索引ファイル」は、単純なテキストファイルではなく「レコードファイル」と「キーファイル」に分かれていて、内部は「バイナリファイル」です。 で、エディタなどで書いた1行が固定長のテキストファイルを扱う場合、COBOLでは「レコード順ファイル」を用います。 なお、一部のCOBOLでは「1行が不定長でも良く、レコード終わりは改行コード」と言う、テキストファイルに特化した「行順ファイル」も扱えますが、古いCOBOLではサポートされていません。 そう言った訳で「元データがエディタで書いたテキストファイルで、それをCOBOLで扱う」と言う場合は、以下のようにします(実際の業務で「よくあるパターン」です) ●テキストインポートプログラムを用意する 1.元データのテキストファイルを「レコード順ファイル」で「INPUTオープン」する 2.実際にCOBOLで操作するデータファイルを「索引ファイル」で「I-Oオープン」し「ファイル無しエラー」を検出した場合は「OUTPUTオープン」する。 3.ソースファイルを「READ xxx NEXT」で読む。「AT END節」が実行された場合はソースファイルを最後まで読んだので全ファイルをクローズして終了。 4.読んだレコードの各項目をMOVE命令で書き出しレコードの各項目に移送する(レコード丸ごとMOVEしてはいけない。入力側と出力側で「項目の桁数」が違う可能性がある) 5.「WRITE xxx」で書き出し、もし「INVALID KEY節」が実行されたら、そのキーのレコードは既存なので「REWRITE xxx」する。つまり、レコードが無ければレコードを追加、レコードがあれば更新する事になる。 6.前の「3.」から繰り返す。 ●本体のプログラム 1.実際にCOBOLで操作するデータファイルを「索引ファイル」で「I-Oオープン」する。エラーを検出した場合は「データファイルなし」としてプログラム終了 2.キーを指定して(レコードのキー項目に値を入れて)「READ」を行なう。 3.新規のレコードを追加する場合は「WRITE xxx」を、既存のレコードの内容を書き換える場合は「REWRITE」を行なう。 4.クローズして終了。 I-Oオープン、OUTPUTオープンした場合、プログラムを終了する場合は必ず「CLOSE xxx」を行なう事。クローズしないで「STOP RUN」した場合、最悪、最後に書いたレコードがファイルに反映されずに終了します。 ちなみに、COBOLで扱える各ファイルの詳細は、以下のようになります。 ・レコード順ファイル 改行コードも含めて固定長であれば、エディタで書いたテキストファイルも読めるが、先頭から順に1レコードづつ読むしか出来ない。 前のレコードに戻ったり、最後のレコードに飛んだりは出来ない。 先頭レコードに戻りたい場合はクローズしてオープンし直す必要がある(REWINDと言う、先頭に戻る文を追加したCOBOLもあるが一般的ではなく、かなり特殊) 索引もキーもなにもないので「同じ内容のレコード」が複数存在する可能性もある。 ・行順ファイル(一部のCOBOLでのみサポート) レコードが固定長ではなく改行コードで区切られる事を除けば、レコード順ファイルと同じ。 ・相対ファイル ファイルの先頭にレコード管理用のヘッダがあり、レコード長は「COBOLが自動で決めた長さ」になっている。 レコードの先頭にはレコード番号がバイナリデータで記録されていて、レコードの各項目もバイナリデータになっている。 テキストファイルではないので、エディタで作る事は不可能。 言うなれば「レコード番号が索引キーになっている索引ファイル」に同等(と言ってもファイルはデータ本体のみで、キーファイルは存在しない) キーが存在しないのでレコードの重複がチェック出来ないので「同じ内容のレコード」が複数存在する可能性もある。 ・索引ファイル COBOLで最も良く使われるファイル。と言うか、この形式のファイルがあるからCOBOLが使われると言っても過言ではない。 キーを指定する事で、特定のレコードをすぐに呼び出す事が出来る。 「READ xxx NEXT」を使えば「キーを指定せず、次のレコードを読む(オープン直後は先頭レコードを読む)」のも可能なので、レコード順ファイルで行なうような「先頭から最後まで順に処理する」と言う事も可能。 「START」を使うと「指定したキーに最も近いレコード」も探せるので「キーが○○から△△までの間だけ処理する」と言う事も可能になる。 索引キーが「キーファイル」としてデータ本体のファイルと別になっている事が多い。 普通は同一キーのレコード重複は許されないが「RECORD KEY句」に「WITH DUPLICATES」を指定すると、同一キーで複数のレコードを存在させられる。 レコードの先頭には削除フラグがバイナリデータで記録されていて、レコードの各項目もバイナリデータになっている。 テキストファイルではないので、エディタで作る事は不可能。 各レコードの「物理的なファイル位置」は「キーファイル」で管理されているので、レコードの物理的な位置はキーの順番に一致しない。最終レコードがファイルの先頭に存在したり、先頭レコードがファイルの末尾に存在したりする可能性もある。
お礼
丁寧なご解答ありがとうございました。 しかし、テキストインポートプログラムを下記のように作成しましたが、一番初めの質問と同じエラーがコンパイル成功後の実行時に発生してしまいます。もう一度、アホな私に原因をお教えいただけないでしょうか? (補足) mokhyou.datを読み込み、n-mokuhyou.datに出力しようとしています。 n-mokuhyou.datは存在させず、OPEN OUTPUT で作成しています。 エラーにはなりますが、n-mokuhyou.datは作成され、エディタで覗くと意味不明な文字がいっぱいです。 そのn-mokuhyou.datを使い、本プログラムを実行しても、同じように読込エラーとなります。 FILE-CONTROL. SELECT URIAGE-MOKUHYOU ASSIGN TO "c:\dat\mokuhyou.dat" . SELECT N-URIAGE-MOKUHYOU ASSIGN TO "c:\dat\n-mokuhyou.dat" ORGANIZATION IS INDEXED ACCESS MODE IS DYNAMIC RECORD KEY IS NUM-SHITEN-CODE. DATA DIVISION. FILE SECTION. FD URIAGE-MOKUHYOU. 01 UM-REC. 05 UM-SHITEN. 10 UM-SHITEN-CODE PIC X(4). 10 UM-SHITEN-MEI PIC X(20). 05 UM-KINGAKU PIC 9(10) OCCURS 12. FD N-URIAGE-MOKUHYOU. 01 NUM-REC. 05 NUM-SHITEN. 10 NUM-SHITEN-CODE PIC X(4). 10 NUM-SHITEN-MEI PIC X(20). 05 NUM-KINGAKU PIC 9(10) OCCURS 12. WORKING-STORAGE SECTION. 01 FLG PIC 9 VALUE 0. 01 I PIC 9(2). PROCEDURE DIVISION. OPEN INPUT URIAGE-MOKUHYOU OPEN OUTPUT N-URIAGE-MOKUHYOU PERFORM UNTIL FLG = 1 READ URIAGE-MOKUHYOU NEXT AT END MOVE 1 TO FLG NOT AT END MOVE UM-SHITEN-CODE TO NUM-SHITEN-CODE MOVE UM-SHITEN-MEI TO NUM-SHITEN-MEI PERFORM VARYING I FROM 1 BY 1 UNTIL I > 10 MOVE UM-KINGAKU(I) TO NUM-KINGAKU(I) END-PERFORM MOVE UM-REC TO NUM-REC REWRITE NUM-REC END-READ END-PERFORM CLOSE URIAGE-MOKUHYOU CLOSE N-URIAGE-MOKUHYOU STOP RUN.
- chie65536
- ベストアンサー率41% (2512/6032)
まず、mokuhyou.datを作成する際に「ACCESS MODE IS DYNAMIC」で「OPEN OUTPUT」して、データファイルとキーファイルを作成しておく事。 正しく作成されればmokuhyou.datとmokuhyou.idxの2つのファイルが出来上がる筈。拡張子.idxのファイルは「キーファイル」で、これを元に「キーでの検索」が行なわれる。 てゆ~か、ファイルを作成してるプログラムは、元々「ACCESS MODE IS DYNAMIC」でアクセスしてた筈。それを「ACCESS MODE IS RANDOM」でアクセスしようとするから、実行時にオープン文でエラーが起きてる訳で。 で、特定のキーで特定のレコードを読みたいなら「ACCESS MODE IS DYNAMIC」で、キー付きファイルをオープンする事。 ×ACCESS MODE IS RANDOM ○ACCESS MODE IS DYNAMIC 実際、特定のキーで特定のレコードを読む場合は、レコードキーに「欲しいレコードのキー値」をセットしておいてから「READ」を行なう。 × OPEN INPUT URIAGE-MOKUHYOU × READ URIAGE-MOKUHYOU ○ OPEN INPUT URIAGE-MOKUHYOU ○ MOVE WK-SHITEN-CODE TO UM-SHITEN-CODE ○ READ URIAGE-MOKUHYOU レコードが無ければ「INVALID KEY」節が実行され、あれば「NOT INVALID KEY」節が実行される。
お礼
すみません。基本的な質問で恐縮ですが、mokuhyou.datのファイルは自分がテストデータをエディタで編集し、mokuhyou.datの名前で保存しただけなのですが、そうではなく、mokuhyou.datは別プログラムから作成すべきということなのでしょうか?
お礼
ありがとうございました。 お礼遅れて申し訳ありませんでした。 実は、言われたとおりやったつもりでしたが、やはりエラーになってしまって、半分あきらめてました。 でも、改めてこちょこちょいじってるうちに成功しました。 そこでまた新たな質問なんですが、 (1)SELECT FILE01 ASSIGN TO "c:\dat\input-file.txt". (2)SELECT FILE01 ASSIGN TO INPUT-FL. OPEN INPUT FILE01 というコードについて、(1)は意味が分かるのですが、(2)はどこからどういうファイルをOPENするのですか?多くのサンプルコードは(2)ですが、そのままコンパイルするとエラーになります。 ローカルフォルダのファイルを使用するという考え自体が違うのですか? 毎回基本的な質問で大変恐縮です。 書籍等を買えば載っているのでしょうが、無精者の私にぜひお力をお貸しください。