はじめに
今回のミニプロジェクトでは、COBOLプログラムとCSV(Comma-Separated Values)ファイルの連携処理を学びます。CSVファイルは、データをカンマ区切りで保存するシンプルなテキストファイル形式で、Excelなどの表計算ソフトや多くのシステムでデータ交換によく使われています。
COBOLプログラムでCSVファイルを読み書きできるようになると、他のシステムとのデータ連携がスムーズになり、活用の幅が広がります。 💪 さっそく、具体的な方法を見ていきましょう!
COBOLでのCSVファイルの扱い方
COBOLでCSVファイルを扱うには、主に以下の手順が必要です。
- ファイル定義 (ENVIRONMENT DIVISION, DATA DIVISION): CSVファイルをCOBOLプログラムで認識させるための定義を行います。
- ファイル操作 (PROCEDURE DIVISION): ファイルを開き (OPEN)、データを読み込み (READ) または書き込み (WRITE)、最後にファイルを閉じる (CLOSE) 処理を行います。
- データ編集 (PROCEDURE DIVISION): 読み込んだCSVデータを項目ごとに分解 (UNSTRING) したり、書き込むデータをCSV形式に組み立てたり (STRING) します。
1. ファイル定義
ENVIRONMENT DIVISION
のFILE-CONTROL
句で、プログラム内で使うファイル名(論理ファイル名)と実際のファイル名(物理ファイル名)を関連付けます。CSVファイルは通常、1行の長さが可変であるため、ORGANIZATION IS LINE SEQUENTIAL
を指定するのが一般的です。これは改行コードを区切りとしてレコードを扱うファイル形式です。
DATA DIVISION
のFILE SECTION
で、FD
句を使ってファイルのレコード構造を定義します。CSVファイルは1行全体のデータを格納する比較的大きな領域(例:PIC X(500)
)として定義し、行の実際の長さは別の変数(DEPENDING ON
句で指定)で管理する方法があります。
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT CSV-INPUT-FILE ASSIGN TO "input.csv"
ORGANIZATION IS LINE SEQUENTIAL.
SELECT OUTPUT-FILE ASSIGN TO "output.dat"
ORGANIZATION IS LINE SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD CSV-INPUT-FILE.
* 可変長レコードとして扱う例
* RECORD IS VARYING IN SIZE FROM 1 TO 500 CHARACTERS
* DEPENDING ON CSV-REC-LEN.
* 固定長として大きな領域を確保する例(後でUNSTRINGで分解)
01 CSV-INPUT-RECORD PIC X(500).
* GnuCOBOLなどでは RECORD VARYING DEPENDING ON も使える
* FD CSV-INPUT-FILE RECORD VARYING DEPENDING ON REC-LENGTH.
* 01 CSV-INPUT-RECORD PIC X(500).
FD OUTPUT-FILE.
01 OUTPUT-RECORD PIC X(80).
WORKING-STORAGE SECTION.
* 可変長レコードの長さを格納する変数 (FDで DEPENDING ON を使う場合)
* 01 REC-LENGTH PIC 9(5) COMP.
* CSVレコードを分解して格納するデータ項目
01 WS-CSV-DATA.
05 WS-FIELD-1 PIC X(10).
05 WS-FIELD-2 PIC X(20).
05 WS-FIELD-3 PIC 9(5).
* CSVレコードを作成するためのデータ項目
01 WS-OUTPUT-FIELDS.
05 WS-OUT-FIELD-1 PIC X(10) VALUE "DATA-A".
05 WS-OUT-FIELD-2 PIC X(20) VALUE "DATA-B".
05 WS-OUT-FIELD-3 PIC 9(5) VALUE 12345.
2. ファイル操作とデータ編集
PROCEDURE DIVISION
で、実際のファイル操作とデータ編集を行います。
CSVファイルの読み込み (READとUNSTRING)
OPEN INPUT
でCSVファイルを開き、READ
文で1行ずつ読み込みます。読み込んだデータはFD
句で定義したレコード領域(例: CSV-INPUT-RECORD
)に格納されます。
読み込んだ1行のデータ(カンマ区切りの文字列)を個々の項目に分解するには、UNSTRING
文を使います。DELIMITED BY ","
でカンマを区切り文字として指定し、分解したデータをINTO
句で指定した変数(例: WS-FIELD-1
, WS-FIELD-2
…)に格納します。
PROCEDURE DIVISION.
OPEN-FILES.
OPEN INPUT CSV-INPUT-FILE.
OPEN OUTPUT OUTPUT-FILE.
READ-PROCESS-WRITE.
* レコード領域を初期化してから読み込むのが安全
MOVE SPACES TO CSV-INPUT-RECORD.
READ CSV-INPUT-FILE
AT END
GO TO CLOSE-FILES
END-READ.
* 読み込んだCSVレコードを分解
UNSTRING CSV-INPUT-RECORD DELIMITED BY ","
INTO WS-FIELD-1
WS-FIELD-2
WS-FIELD-3
* 必要に応じて TALLYING IN や COUNT IN を指定
END-UNSTRING.
* 分解したデータを処理 (ここでは出力ファイルへ書き込む例)
MOVE SPACES TO OUTPUT-RECORD. *> 出力レコード初期化
STRING WS-FIELD-1 DELIMITED BY SIZE
" " DELIMITED BY SIZE *> 区切りスペース
WS-FIELD-2 DELIMITED BY SIZE
" " DELIMITED BY SIZE
WS-FIELD-3 DELIMITED BY SIZE *> 数値項目も転記
INTO OUTPUT-RECORD.
WRITE OUTPUT-RECORD.
* 次のレコードを処理するためにループ
GO TO READ-PROCESS-WRITE.
CLOSE-FILES.
CLOSE CSV-INPUT-FILE
OUTPUT-FILE.
STOP RUN.
READ
文を実行する前に、レコード領域(CSV-INPUT-RECORD
)をMOVE SPACES TO ...
などで初期化することが推奨されます。これにより、前のレコードのデータが残ってしまうのを防げます。
CSVファイルへの書き込み (STRINGとWRITE)
個々のデータ項目をカンマ区切りの1行の文字列に組み立てるには、STRING
文を使います。DELIMITED BY
句で各項目とカンマを指定し、結合した結果をINTO
句で指定した出力レコード領域に格納します。
組み立てたデータをファイルに書き込むには、WRITE
文を使用します。ORGANIZATION IS LINE SEQUENTIAL
で定義したファイルにWRITE
すると、自動的に改行コードが付加されます。
PROCEDURE DIVISION.
OPEN-FILES.
OPEN OUTPUT CSV-OUTPUT-FILE. *> CSV出力ファイルを開く
WRITE-CSV-RECORD.
* 出力するデータ項目に値を設定 (例: WS-OUTPUT-FIELDS)
* ...
* データ項目をカンマ区切りで連結してCSVレコードを作成
MOVE SPACES TO CSV-OUTPUT-RECORD. *> 出力レコード初期化
STRING WS-OUT-FIELD-1 DELIMITED BY " " *> 末尾スペース除去
"," DELIMITED BY SIZE
WS-OUT-FIELD-2 DELIMITED BY " "
"," DELIMITED BY SIZE
WS-OUT-FIELD-3 DELIMITED BY SIZE *> 数値項目
INTO CSV-OUTPUT-RECORD
* 必要に応じて WITH POINTER を指定
END-STRING.
* 組み立てたCSVレコードをファイルに書き込む
WRITE CSV-OUTPUT-RECORD.
* 他のレコードも書き込む場合は処理を繰り返す...
CLOSE-FILES.
CLOSE CSV-OUTPUT-FILE.
STOP RUN.
STRING
文で文字列項目を連結する際、DELIMITED BY " "
(スペース2つ)やDELIMITED BY SIZE
を使い分けることで、項目の前後の不要なスペースを取り除くことができます。数値項目は通常、DELIMITED BY SIZE
でそのまま連結します。
サンプルプログラム例
ここでは、簡単なCSV読み込みと書き込みのサンプルを示します。
CSV読み込みプログラム (input.csv -> report.txt)
input.csv
1001,Yamada Taro,50000
1002,Sato Hanako,65000
1003,"Suzuki, Jiro",72000
read_csv.cbl
IDENTIFICATION DIVISION.
PROGRAM-ID. READ-CSV-SAMPLE.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT CSV-FILE ASSIGN TO "input.csv"
ORGANIZATION IS LINE SEQUENTIAL.
SELECT REPORT-FILE ASSIGN TO "report.txt"
ORGANIZATION IS LINE SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD CSV-FILE.
01 CSV-RECORD PIC X(100).
FD REPORT-FILE.
01 REPORT-RECORD PIC X(80).
WORKING-STORAGE SECTION.
01 WS-CSV-FIELDS.
05 WS-ID PIC X(4).
05 WS-NAME PIC X(20).
05 WS-SALARY PIC 9(7). *> UNSTRINGでは数値変換しない想定
01 WS-WORK-AREAS.
05 WS-SALARY-DISP PIC ZZZ,ZZ9.
05 WS-EOF-FLAG PIC X VALUE 'N'.
88 EOF VALUE 'Y'.
PROCEDURE DIVISION.
MAIN-PROCEDURE.
OPEN INPUT CSV-FILE
OUTPUT REPORT-FILE.
PERFORM UNTIL EOF
READ CSV-FILE
AT END
SET EOF TO TRUE
NOT AT END
PERFORM PROCESS-RECORD
END-READ
END-PERFORM.
CLOSE CSV-FILE
REPORT-FILE.
STOP RUN.
PROCESS-RECORD.
* CSVレコードを分解 (簡易的な処理)
UNSTRING CSV-RECORD DELIMITED BY ","
INTO WS-ID
WS-NAME
WS-SALARY *> 文字列として受け取る
END-UNSTRING.
* レポート形式に編集して出力
MOVE WS-SALARY TO WS-SALARY-DISP. *> 表示用に編集
MOVE SPACES TO REPORT-RECORD.
STRING "ID:" DELIMITED BY SIZE
WS-ID DELIMITED BY " "
", Name:" DELIMITED BY SIZE
WS-NAME DELIMITED BY " "
", Salary:" DELIMITED BY SIZE
WS-SALARY-DISP DELIMITED BY " " *> 先頭スペース除去
INTO REPORT-RECORD.
WRITE REPORT-RECORD.
report.txt
(実行結果)
ID:1001, Name:Yamada Taro , Salary: 50,000
ID:1002, Name:Sato Hanako , Salary: 65,000
ID:1003, Name:"Suzuki, Jiro" , Salary: 72,000
CSV書き込みプログラム (data -> output.csv)
write_csv.cbl
IDENTIFICATION DIVISION.
PROGRAM-ID. WRITE-CSV-SAMPLE.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT CSV-OUT-FILE ASSIGN TO "output.csv"
ORGANIZATION IS LINE SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD CSV-OUT-FILE.
01 CSV-OUT-RECORD PIC X(100).
WORKING-STORAGE SECTION.
01 WS-PRODUCT-DATA.
05 PRODUCT-CODE PIC X(5).
05 PRODUCT-NAME PIC X(30).
05 PRICE PIC 9(6).
05 STOCK-QTY PIC 9(4).
PROCEDURE DIVISION.
MAIN-PROCEDURE.
OPEN OUTPUT CSV-OUT-FILE.
* サンプルデータ1の書き込み
MOVE "P0001" TO PRODUCT-CODE.
MOVE "High Quality Widget" TO PRODUCT-NAME.
MOVE 15000 TO PRICE.
MOVE 120 TO STOCK-QTY.
PERFORM CREATE-AND-WRITE-CSV.
* サンプルデータ2の書き込み (名前にカンマを含む例)
MOVE "P0002" TO PRODUCT-CODE.
MOVE 'Standard Gadget, Model A' TO PRODUCT-NAME.
MOVE 8500 TO PRICE.
MOVE 300 TO STOCK-QTY.
PERFORM CREATE-AND-WRITE-CSV.
CLOSE CSV-OUT-FILE.
STOP RUN.
CREATE-AND-WRITE-CSV.
* データ項目をCSV形式に組み立てる
MOVE SPACES TO CSV-OUT-RECORD.
STRING FUNCTION TRIM(PRODUCT-CODE) DELIMITED BY SIZE
"," DELIMITED BY SIZE
* カンマを含む可能性のある項目はダブルクォートで囲む
'"' FUNCTION TRIM(PRODUCT-NAME) '"' DELIMITED BY SIZE
"," DELIMITED BY SIZE
PRICE DELIMITED BY SIZE *> 数値はそのまま
"," DELIMITED BY SIZE
STOCK-QTY DELIMITED BY SIZE
INTO CSV-OUT-RECORD.
* ファイルに書き込み
WRITE CSV-OUT-RECORD.
output.csv
(実行結果)
P0001,"High Quality Widget",15000,120
P0002,"Standard Gadget, Model A",008500,300
上記のサンプルは基本的な例です。実際のCSV処理では、以下のような点を考慮する必要があります。
- ダブルクォーテーションの扱い: フィールド内にカンマやダブルクォーテーション自体が含まれる場合、フィールド全体をダブルクォーテーションで囲むのが一般的です。読み込み時にはこれらの処理、書き込み時には適切な引用符付けが必要です。
UNSTRING
やSTRING
だけでは複雑なケースに対応しきれない場合があり、1文字ずつ検査するロジックが必要になることもあります。 - 文字コード: CSVファイルの文字コード(Shift_JIS, UTF-8など)とCOBOLプログラムが扱う文字コードが異なる場合、文字化けが発生する可能性があります。必要に応じて文字コード変換処理を組み込むか、コンパイラのオプションで対応します。
- 空のフィールド: CSVファイルでは
,,
のようにフィールドが空の場合があります。UNSTRING
でこれらを正しく処理できるか確認が必要です(受け取る変数を適切に初期化するなど)。 - エラーハンドリング: ファイルI/Oエラー(ファイルが見つからない、書き込み権限がないなど)や、データ形式エラー(数値項目に文字が入っているなど)に対するエラー処理を実装することが重要です。
FILE STATUS
句やINVALID KEY
句、AT END
句などを活用します。
まとめ
今回は、COBOLプログラムでCSVファイルを扱う基本的な方法を学びました。UNSTRING
文によるデータの分解とSTRING
文によるデータの組み立てが中心となります。
CSVファイルは、異なるシステム間でデータをやり取りするための重要な形式です。COBOLでCSV連携ができるようになれば、既存のCOBOL資産を活かしつつ、他のシステムとの連携を強化できます。🎉
実際の業務では、より複雑なCSVフォーマットやエラー処理に対応する必要がありますが、今回の内容がその第一歩となれば幸いです。ぜひ、ご自身の環境でサンプルプログラムを動かしてみてください!
参考情報
- GnuCOBOL Programmer’s Guide: GnuCOBOLの公式ドキュメント。ファイル処理やSTRING/UNSTRING文の詳細な説明があります。(URLはGnuCOBOLのバージョンによって異なる可能性があります。Web検索で “GnuCOBOL Programmer’s Guide” を探してください。)
- 富士通 NetCOBOL V12.2.1 COBOL文法書: STRING文、UNSTRING文などの詳細な仕様が記載されています。(CSV連携に特化した章はありませんが、各文法の説明が参考になります。) https://software.fujitsu.com/jp/manual/manualfiles/M200005/b1ws1101/04/b1ws1101-04-PDU-STRING.html https://software.fujitsu.com/jp/manual/manualfiles/M200005/b1ws1101/04/b1ws1101-04-PDU-UNSTRING.html
- Micro Focus Visual COBOL Documentation: Micro Focus COBOLのドキュメントにも、ファイル処理や文字列操作に関する詳細情報が含まれています。(特定のURLはバージョンにより異なります)
- SimoTime – COBOL & Mainframe Tutorials: COBOLに関する多くのサンプルプログラムや解説記事が掲載されています。CSV処理のサンプルもあります。 Create a CSV File with COBOL / Read a CSV File with COBOL
※ 各COBOL処理系の正確な文法や仕様については、必ず公式のマニュアルをご確認ください。
コメント