COBOL File Handling: OPEN, READ, WRITE, REWRITE, and CLOSE

File I/O is at the heart of COBOL's purpose. Every batch job processes input files, updates master files, and writes output — all through COBOL's structured file handling verbs. Understanding the full lifecycle from SELECT through CLOSE, and the difference between sequential and random access patterns, is essential for production mainframe development.
File Declaration: SELECT and FD
Every file used by a program must be declared in two places: the SELECT statement in the FILE-CONTROL section of the ENVIRONMENT DIVISION, and an FD (File Description) entry in the FILE SECTION of the DATA DIVISION.
Sequential File (QSAM)
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT TRANSACTION-FILE
ASSIGN TO TRANSIN
ORGANIZATION IS SEQUENTIAL
ACCESS MODE IS SEQUENTIAL
FILE STATUS IS WS-TRAN-STATUS.
DATA DIVISION.
FILE SECTION.
FD TRANSACTION-FILE
RECORDING MODE IS F
BLOCK CONTAINS 0 RECORDS
RECORD CONTAINS 80 CHARACTERS.
01 TRANSACTION-RECORD PIC X(80).ASSIGN TO TRANSIN connects the logical file name to the JCL DD statement named TRANSIN. The physical dataset path is specified in JCL — the COBOL program never knows the actual dataset name, only the ddname.
RECORDING MODE IS F means fixed-length records. FB (fixed blocked) is specified in JCL; the COBOL compiler sees F. BLOCK CONTAINS 0 tells the runtime to use the block size from the JCL DD statement or dataset label.
VSAM KSDS File (Random Access)
FILE-CONTROL.
SELECT CUSTOMER-MASTER
ASSIGN TO CUSTMST
ORGANIZATION IS INDEXED
ACCESS MODE IS DYNAMIC
RECORD KEY IS CM-CUSTOMER-ID
ALTERNATE RECORD KEY IS CM-SSN
WITH DUPLICATES
FILE STATUS IS WS-CUST-STATUS.
FD CUSTOMER-MASTER
RECORD CONTAINS 200 CHARACTERS.
01 CUSTOMER-MASTER-RECORD.
05 CM-CUSTOMER-ID PIC X(10).
05 CM-SSN PIC X(11).
05 CM-LAST-NAME PIC X(25).
05 CM-FIRST-NAME PIC X(15).
05 CM-BALANCE PIC S9(11)V99 COMP-3.
05 CM-STATUS PIC X(2).
05 CM-OPEN-DATE PIC 9(8).
05 FILLER PIC X(110).ORGANIZATION IS INDEXED defines a KSDS. ACCESS MODE IS DYNAMIC enables both sequential and random access within the same program. RECORD KEY IS CM-CUSTOMER-ID names the primary key — it must be a field within the FD record. ALTERNATE RECORD KEY provides a secondary access path.
FILE STATUS Codes
Always declare a FILE STATUS field and check it after every file operation:
WORKING-STORAGE SECTION.
01 WS-FILE-STATUSES.
05 WS-CUST-STATUS PIC XX VALUE SPACES.
88 CUST-OK VALUE '00'.
88 CUST-EOF VALUE '10'.
88 CUST-NOT-FOUND VALUE '23'.
88 CUST-DUP-KEY VALUE '22'.
88 CUST-LOCKED VALUE '9D'.
88 CUST-OPEN-ERR VALUE '90' '91' '92' '93' '94' '95'.Key FILE STATUS codes:
| Code | Meaning |
|---|---|
00 | Successful completion |
02 | Duplicate alternate key (non-fatal on READ) |
10 | End of file reached |
22 | Duplicate primary key on WRITE |
23 | Record not found on random READ/DELETE |
24 | Boundary violation (WRITE past end of relative file) |
30 | Permanent I/O error |
9D | Record locked by another task |
9x | VSAM-specific error — check VSAM return/reason codes |
OPEN
Files must be opened before any I/O. The mode determines what operations are permitted:
OPEN INPUT TRANSACTION-FILE. *> read-only
OPEN OUTPUT REPORT-FILE. *> write only (creates/replaces)
OPEN I-O CUSTOMER-MASTER. *> read and update (REWRITE/DELETE)
OPEN EXTEND AUDIT-LOG-FILE. *> append to end of sequential file
IF NOT CUST-OK
DISPLAY 'OPEN FAILED: ' WS-CUST-STATUS
PERFORM ABEND-OPEN-FAILURE
END-IF.Multiple files can be opened in a single statement:
OPEN INPUT CUSTOMER-FILE
PRODUCT-FILE
OUTPUT REPORT-FILE.Always check FILE STATUS immediately after OPEN. A 9x status on OPEN means the file is unavailable, misallocated, or the DD statement is missing — the program cannot proceed.
READ: Sequential
For sequential access, READ retrieves the next record in order:
READ-NEXT-RECORD.
READ CUSTOMER-MASTER
AT END SET CUST-EOF TO TRUE
NOT AT END PERFORM PROCESS-CUSTOMER-RECORD
END-READ.The INTO phrase copies the record into a working-storage area (recommended for structured access):
READ TRANSACTION-FILE INTO WS-TRANSACTION-WORK
AT END SET TRAN-EOF TO TRUE
END-READ.Without INTO, the data is available in the FD record area directly. Using INTO gives you a working-storage copy with full COMP-3 field access.
READ: Random
Random READ retrieves a specific record by key:
RANDOM-READ-CUSTOMER.
MOVE WS-SEARCH-ID TO CM-CUSTOMER-ID
READ CUSTOMER-MASTER
EVALUATE TRUE
WHEN CUST-OK
PERFORM PROCESS-FOUND-CUSTOMER
WHEN CUST-NOT-FOUND
MOVE 'CUSTOMER NOT ON FILE' TO WS-MESSAGE
SET WS-ERROR-FOUND TO TRUE
WHEN CUST-LOCKED
PERFORM HANDLE-RECORD-LOCKED
WHEN OTHER
PERFORM HANDLE-READ-ERROR
END-EVALUATE.Move the key value to the RECORD KEY field in the FD record before issuing the READ. The runtime uses that value to locate the record.
READ with Alternate Key
MOVE WS-SSN TO CM-SSN
READ CUSTOMER-MASTER KEY IS CM-SSN
INVALID KEY
PERFORM HANDLE-SSN-NOT-FOUND
NOT INVALID KEY
PERFORM PROCESS-FOUND-RECORD
END-READ.INVALID KEY is the older form of AT END/NOT AT END for keyed reads. Modern code prefers checking FILE STATUS via 88-level conditions.
READ: Sequential Browsing of VSAM (START + READ NEXT)
With ACCESS MODE IS DYNAMIC, you can position to a key and read sequentially from that point:
BROWSE-FROM-KEY.
MOVE WS-START-ID TO CM-CUSTOMER-ID
START CUSTOMER-MASTER
KEY >= CM-CUSTOMER-ID
IF NOT CUST-OK
PERFORM HANDLE-START-ERROR
EXIT PARAGRAPH
END-IF
PERFORM UNTIL CUST-EOF OR WS-BROWSE-DONE
READ CUSTOMER-MASTER NEXT
AT END SET CUST-EOF TO TRUE
END-READ
IF CUST-OK
PERFORM PROCESS-BROWSE-RECORD
END-IF
END-PERFORM.START positions the file cursor without reading a record. READ NEXT (or READ ... NEXT RECORD) then reads sequentially from that position.
WRITE
WRITE adds a new record to an output or I-O file:
*> Sequential output:
MOVE WS-REPORT-LINE TO REPORT-RECORD
WRITE REPORT-RECORD
AFTER ADVANCING 1 LINE.
*> VSAM random write:
MOVE WS-NEW-CUSTOMER-DATA TO CUSTOMER-MASTER-RECORD
WRITE CUSTOMER-MASTER-RECORD
INVALID KEY
MOVE 'DUPLICATE CUSTOMER ID' TO WS-ERROR-MSG
SET WS-ERROR-FOUND TO TRUE
NOT INVALID KEY
ADD 1 TO WS-RECORDS-WRITTEN
END-WRITE.AFTER ADVANCING n LINES controls printer spacing for report files. AFTER ADVANCING PAGE issues a form feed.
INVALID KEY fires when a duplicate primary key exists. Always handle it — a duplicate write to a KSDS without error handling silently fails and raises FILE STATUS 22.
REWRITE
REWRITE updates an existing record in place. For sequential files, it replaces the last record returned by READ. For VSAM random access, it replaces the record matching the current key:
UPDATE-CUSTOMER-BALANCE.
MOVE WS-ACCOUNT-ID TO CM-CUSTOMER-ID
READ CUSTOMER-MASTER
IF CUST-NOT-FOUND
PERFORM HANDLE-NOT-FOUND
ELSE IF CUST-OK
ADD WS-TRANSACTION-AMOUNT TO CM-BALANCE
REWRITE CUSTOMER-MASTER-RECORD
IF NOT CUST-OK
PERFORM HANDLE-REWRITE-ERROR
END-IF
END-IF.The sequence is always: READ → modify fields in the record area → REWRITE. Attempting REWRITE without a prior successful READ produces unpredictable results.
DELETE
DELETE removes a record from a VSAM file. For KSDS files opened I-O, DELETE requires a prior READ:
CLOSE-CUSTOMER-ACCOUNT.
MOVE WS-ACCOUNT-TO-CLOSE TO CM-CUSTOMER-ID
READ CUSTOMER-MASTER
IF CUST-OK
DELETE CUSTOMER-MASTER RECORD
IF NOT CUST-OK
PERFORM HANDLE-DELETE-ERROR
END-IF
END-IF.CLOSE
Always close files before the program ends:
FINALIZE-PROGRAM.
CLOSE CUSTOMER-MASTER
TRANSACTION-FILE
REPORT-FILE.Failing to CLOSE leaves enqueue locks on VSAM files, preventing other jobs from accessing them. On z/OS, abnormal program termination (ABEND) automatically releases locks, but a normal STOP RUN without CLOSE leaves files open.
Complete Batch Update Example
PROCEDURE DIVISION.
MAIN-LOGIC.
PERFORM OPEN-ALL-FILES
PERFORM READ-FIRST-TRANSACTION
PERFORM UPDATE-LOOP UNTIL TRAN-EOF
PERFORM CLOSE-ALL-FILES
PERFORM DISPLAY-TOTALS
STOP RUN.
OPEN-ALL-FILES.
OPEN INPUT TRANSACTION-FILE
OPEN I-O CUSTOMER-MASTER
OPEN OUTPUT EXCEPTION-REPORT
IF NOT TRAN-OK OR NOT CUST-OK OR NOT EXCPT-OK
DISPLAY 'OPEN FAILED - TERMINATING'
STOP RUN
END-IF.
UPDATE-LOOP.
MOVE WS-TRAN-ACCOUNT-ID TO CM-CUSTOMER-ID
READ CUSTOMER-MASTER
EVALUATE TRUE
WHEN CUST-NOT-FOUND
PERFORM WRITE-EXCEPTION-NOT-FOUND
WHEN CUST-OK
PERFORM APPLY-TRANSACTION
PERFORM REWRITE-CUSTOMER
WHEN OTHER
PERFORM WRITE-EXCEPTION-IO-ERROR
END-EVALUATE
PERFORM READ-NEXT-TRANSACTION.
APPLY-TRANSACTION.
ADD WS-TRAN-AMOUNT TO CM-BALANCE
ADD 1 TO WS-UPDATES-APPLIED.
REWRITE-CUSTOMER.
REWRITE CUSTOMER-MASTER-RECORD
IF NOT CUST-OK
PERFORM WRITE-EXCEPTION-REWRITE-ERROR
SUBTRACT WS-TRAN-AMOUNT FROM CM-BALANCE
END-IF.
CLOSE-ALL-FILES.
CLOSE TRANSACTION-FILE
CUSTOMER-MASTER
EXCEPTION-REPORT.Next Steps
File handling gives you the ability to read and update persistent data. The next capability is table handling — OCCURS, SEARCH, and INDEXED BY for in-memory arrays and lookup tables. See COBOL Table Handling, or return to the COBOL Mastery course.
