COBOL COBOL 2014 (ISO/IEC 1989:2014), built with GnuCOBOL 3.x ·
✓ verified by execution on 2026-08-16
File I/O is what COBOL was built for. A course that stops before it teaches file handling has only taught a toy language, not the one that runs global payroll systems. COBOL can process massive files efficiently because its data model is built directly around the concept of records.
Every sequential file program requires three structural elements:
The FILE-CONTROL paragraph to link the physical file to an internal name.
The FILE SECTION and FD (File Description) to define the memory buffer.
The OPEN, READ / WRITE, and CLOSE statements in the PROCEDURE DIVISION.
Linking the File: FILE-CONTROL
Before you can read a file, COBOL needs to know where it is and how it is organized. This is done in the ENVIRONMENT DIVISION.
ENVIRONMENT DIVISION. INPUT-OUTPUT SECTION. FILE-CONTROL. SELECT IN-FILE ASSIGN TO 'demo.txt' ORGANIZATION IS LINE SEQUENTIAL.
The SELECT statement binds the physical file (demo.txt) to the program’s internal identifier (IN-FILE).
Using ORGANIZATION IS LINE SEQUENTIAL means the file is a standard text file where each record is separated by a newline (delimiter character). This is the easiest type of file to work with because it can be opened in any text editor.
Defining the Buffer: FD
The DATA DIVISION must contain a FILE SECTION where you describe the layout of the file’s records.
DATA DIVISION. FILE SECTION. FD IN-FILE. 01 IN-REC PIC X(20).
The FD (File Description) acts as a window to the physical file. The 01 level immediately below it defines the structure of the memory buffer.
Here is a visual representation of how the FD buffer maps over physical file records:
When you execute a READ statement, COBOL moves exactly one record from the disk into the FD buffer. You process it, then READ again to slide the buffer to the next record.
Writing a Sequential File
To write data, you OPEN OUTPUT, move data into the FD buffer, and call WRITE.
cobol✓ verified output
IDENTIFICATION DIVISION. PROGRAM-ID. WRITE-SEQ. ENVIRONMENT DIVISION. INPUT-OUTPUT SECTION. FILE-CONTROL. SELECT OUT-FILE ASSIGN TO 'demo.txt' ORGANIZATION IS LINE SEQUENTIAL. DATA DIVISION. FILE SECTION. FD OUT-FILE. 01 OUT-REC PIC X(20). WORKING-STORAGE SECTION. PROCEDURE DIVISION. OPEN OUTPUT OUT-FILE. MOVE 'FIRST RECORD' TO OUT-REC. WRITE OUT-REC. MOVE 'SECOND RECORD' TO OUT-REC. WRITE OUT-REC. CLOSE OUT-FILE. DISPLAY 'File written.' STOP RUN.
Output
File written.
Your output
Notice that you WRITE the record variable (OUT-REC), not the file name (OUT-FILE).
Reading with the AT END Loop
A common misconception is that the READ statement automatically loops through the whole file. In reality, READ fetches exactly one record. Let’s see what happens if we call it just once without a loop:
Predict the outputcobol
Read the code. What exactly will it print? Commit to an answer before you look.
ID DIVISION. PROGRAM-ID. P. ENVIRONMENT DIVISION. INPUT-OUTPUT SECTION. FILE-CONTROL. SELECT F ASSIGN 'f' ORGANIZATION LINE SEQUENTIAL. DATA DIVISION. FILE SECTION. FD F. 01 R PIC X(5). PROCEDURE DIVISION. OPEN OUTPUT F. MOVE 'APPLE' TO R. WRITE R. MOVE 'GRAPE' TO R. WRITE R. CLOSE F. OPEN INPUT F. READ F AT END CONTINUE END-READ. DISPLAY 'Found: ' R. STOP RUN.
Output
Found: APPLE
You predicted
To process a whole file, you wrap it in a PERFORM UNTIL loop and use the AT END clause.
cobol✓ verified output
IDENTIFICATION DIVISION. PROGRAM-ID. READ-SEQ. ENVIRONMENT DIVISION. INPUT-OUTPUT SECTION. FILE-CONTROL. SELECT IN-FILE ASSIGN TO 'demo.txt' ORGANIZATION IS LINE SEQUENTIAL. DATA DIVISION. FILE SECTION. FD IN-FILE. 01 IN-REC PIC X(20). WORKING-STORAGE SECTION. 01 WS-EOF PIC X VALUE 'N'. PROCEDURE DIVISION. *> Setup: Create the file first OPEN OUTPUT IN-FILE. MOVE 'FIRST RECORD' TO IN-REC. WRITE IN-REC. MOVE 'SECOND RECORD' TO IN-REC. WRITE IN-REC. CLOSE IN-FILE. *> The actual read loop OPEN INPUT IN-FILE. PERFORM UNTIL WS-EOF = 'Y' READ IN-FILE AT END MOVE 'Y' TO WS-EOF NOT AT END DISPLAY 'Read: ' IN-REC END-READ END-PERFORM. CLOSE IN-FILE. STOP RUN.
Output
Read: FIRST RECORD
Read: SECOND RECORD
Your output
This specific READ loop is the exact shape of essentially every batch program ever written in COBOL. The NOT AT END block ensures that you do not process garbage data when the file runs out of records. Finally, the CLOSE statement flushes the buffers and releases the file lock.
Check yourself
What does the `SELECT` statement do in the `FILE-CONTROL` paragraph?
Reveal answer
It assigns an internal file name to an external physical file path — SELECT simply binds your program's internal file name (e.g. IN-FILE) to an external file on disk (like 'data.txt').
Why must you wrap `READ` in a `PERFORM UNTIL` loop?
Reveal answer
READ only fetches one record at a time — READ fetches exactly one record. To process a whole file, you must loop until the AT END condition triggers.
Where do you define the exact layout of the records being read?
Reveal answer
In the FILE SECTION, immediately after the FD — The FD (File Description) is followed by an 01 level that maps the exact structure of the record buffer.
Challenges
Challenge 1 +10 XP
Write a third record containing the text 'THIRD RECORD' to the file.
cobol✓ solution verified at build time
COBOL has no in-browser runtime, so this one is pen-and-paper: work out what the
fixed code should be, then open the solution and compare. The expected output
below is real — it came from compiling the solution with GnuCOBOL when this page
was built.
Test 1 — expects "Done\n"
Need a hint? (−25% XP)
MOVE the text to OUT-REC, then WRITE OUT-REC.
Show solution (0 XP)
IDENTIFICATION DIVISION.PROGRAM-ID. WRITE-CHAL.ENVIRONMENT DIVISION.INPUT-OUTPUT SECTION.FILE-CONTROL. SELECT OUT-FILE ASSIGN TO 'chal.txt' ORGANIZATION IS LINE SEQUENTIAL.DATA DIVISION.FILE SECTION.FD OUT-FILE.01 OUT-REC PIC X(20).WORKING-STORAGE SECTION.PROCEDURE DIVISION. OPEN OUTPUT OUT-FILE. MOVE 'FIRST RECORD' TO OUT-REC. WRITE OUT-REC. MOVE 'SECOND RECORD' TO OUT-REC. WRITE OUT-REC. MOVE 'THIRD RECORD' TO OUT-REC. WRITE OUT-REC. CLOSE OUT-FILE. DISPLAY 'Done'. STOP RUN.
🐞 Bug Hunt+15 XP
This program has a bug. It is supposed to read all records, but instead, it processes the last record twice! Fix the read loop so it doesn't process garbage data at EOF.
This code runs. It just does the wrong thing. Read it, find the defect,
fix it — the tests below decide when you are right.
cobol✓ solution verified at build time
COBOL has no in-browser runtime, so this one is pen-and-paper: work out what the
fixed code should be, then open the solution and compare. The expected output
below is real — it came from compiling the solution with GnuCOBOL when this page
was built.
Test 1 — expects "Read: FIRST RECORD \nRead: SECOND RECORD \nRead: THIRD RECORD \n"
Need a hint? (−25% XP)
If AT END triggers, the buffer is not updated, but the code still executes the DISPLAY statement. You should use NOT AT END or an IF condition.
Show solution (0 XP)
IDENTIFICATION DIVISION.PROGRAM-ID. BUGHUNT-SEQ.ENVIRONMENT DIVISION.INPUT-OUTPUT SECTION.FILE-CONTROL. SELECT IN-FILE ASSIGN TO 'chal.txt' ORGANIZATION IS LINE SEQUENTIAL.DATA DIVISION.FILE SECTION.FD IN-FILE.01 IN-REC PIC X(20).WORKING-STORAGE SECTION.01 WS-EOF PIC X VALUE 'N'.PROCEDURE DIVISION. *> Setup: Create the file first OPEN OUTPUT IN-FILE. MOVE 'FIRST RECORD' TO IN-REC. WRITE IN-REC. MOVE 'SECOND RECORD' TO IN-REC. WRITE IN-REC. MOVE 'THIRD RECORD' TO IN-REC. WRITE IN-REC. CLOSE IN-FILE. OPEN INPUT IN-FILE. PERFORM UNTIL WS-EOF = 'Y' READ IN-FILE AT END MOVE 'Y' TO WS-EOF NOT AT END DISPLAY 'Read: ' IN-REC END-READ END-PERFORM. CLOSE IN-FILE. STOP RUN.