Reading and Writing Sequential Files

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:

  1. The FILE-CONTROL paragraph to link the physical file to an internal name.
  2. The FILE SECTION and FD (File Description) to define the memory buffer.
  3. 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:

Record 1 Record 2 Record 3 FD Buffer (IN-REC)

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.

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 output cobol

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

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       

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.