The COBOL file management is for processing files (with or without creation).
Renaming, file deletion, file copy, setting file rights is not possible in COBOL but e.g. in JCL or manually.
The file management appears in these parts of a COBOL source code:
ENVIRONMENT DIVISION, INPUT‑OUTPUT SECTION (which file)
DATA DIVISION, FILE SECTION (what is the record structure of the file)
PROCEDURE DIVISION (open, close, I/O)
ENVIRONMENT DIVISION, INPUT‑OUTPUT SECTION, FILE-CONTROL:
the SELECT command defines the logical filename (COBOL name)
the ASSIGN TO clause defines the physical filename (equals with the DD name from the launcing JCL file)
the ORGANIZATION IS clause defines the logical file type
the rest of the clauses are dependent on the logical file type
The ORGANIZATION can be:
SEQUENTIAL
LINE SEQUENTIAL
BINARY SEQUENTIAL
INDEXED
RELATIVE
The possible organization type depends on the dataset type but also on the access mode the developer chooses. PS, SDS files can be organized only as sequential. VSAM KSDS can be organized as sequential and indexed. VSAM ESDS can be as sequential only. VSAM RRDS can be as relative only.
Clauses for -/LINE/BINARY SEQUENTIAL:
FILE STATUS (after all operations receives the status code, optional, but in modern COBOL programming it is necessary)
Clauses for INDEXED:
ACCESS MODE (how the records are reached; optional, default is SEQUENTIAL)
RECORD KEY (which field represents the primary key by which the data is ordered)
ALTERNATE RECORD KEY (secondary key, optional)
for ALTERNATE RECORD KEY clause WITH DUPLICATES (lets the system accept duplicated keys; optional, leaving it out results unique keys)
FILE STATUS (after all operations receives the status code, optional, but in modern COBOL programming it is necessary)
Clauses for RELATIVE:
ACCESS MODE (how the records are reached; optional, default is SEQUENTIAL)
RELATIVE KEY (which field represents the record number by which the data is registered)
FILE STATUS (after all operations receives the status code; optional, but in modern COBOL programming it is necessary)
ACCESS MODE:
SEQUENTIAL (sequential reading in order follows the key or record number; for processing the whole file)
RANDOM (key- or record number-based access; for direct query of a record)
DYNAMIC (hybrid, sequential and random operations can be used together; modern processing)
DATA DIVISION, FILE SECTION:
here are the logical file record structures
an FD (File Description) paragraph contains the logical filename which was defined in the ENVIRONMENT DIVISION, followed by the record structure
an SD (Short Description) paragraph contains the logical filename rendered to a buffer memory only; such file is handled only in logical form, there are no counterpart in the ENVIRONMENT DIVISION
optional RECORD CONTAINS and DATA RECORD IS clauses
optional RECORDING MODE clause
under the FD and SD paragraph headers, the corresponding record structure is defined; this structure will be used for every I/O operation, referred by the variable name of the structure
the record structure must start on 01st level and must not be BASED
in case of more files, the logical filenames and their corresponding record names must be unique
the record structure will be available only when the file is open
The RECORD CONTAINS defines the record size which is usually automatically detected from the record structure. It is necessary only when
the record size is not given by the record structure (e.g. more 01-level records or REDEFINES)
the developer wants to explicitly show the size
if the developer wants to explicitly tell the compiler that the record has fixed length
The DATA RECORD IS clause defines which structure will be used as file element, this is usually done automatically. It is necessary only when
more 01-level records form the file element or REDEFINES
the record structure is stored in a different group e.g. in a copybook with more records inside
the records are in different places under the SECTION, not directly under the FD/SD line.
The RECORDING MODE clause is optional, defines the length type of the record:
F (fixed length, FB)
V (variable length, VB)
U (undefined e.g. LOADLIB)
EXAMPLE FOR SETTING UP THE ENVIRONMENT, SEQUENTIAL FILE:
EXAMPLE FOR SETTING UP THE RECORD STRUCTURE, SEQUENTIAL FILE:
EXAMPLE FOR SETTING UP THE ENVIRONMENT, INDEXED FILE:
EXAMPLE FOR SETTING UP THE RECORD STRUCTURE, INDEXED FILE:
EXAMPLE FOR SETTING UP THE ENVIRONMENT, RELATIVE FILE:
EXAMPLE FOR SETTING UP THE RECORD STRUCTURE, RELATIVE FILE:
Reading, writing is possible only when the file is open. In case the file os not open, any I/O operation raises a runtime error.
Upon opening the file, the file buffer defined under the FILE SECTION will be initialized. The file element structure will be usable as a WORKING-STORAGE structure but it will be available only when the file is open.
After finishing the process, the file must be closed. In case the file is not closed, at the and of the execution the system will close it, however closing explicitly within the code is advised.
The OPEN command opens a file and defines the opening mode:
INPUT
OUTPUT
I-O
EXTEND
Changing the opening mode is not possible within an opened status. Close the file first then open it in another mode.
OUTPUT mode:
upon opening, the file will be truncated to zero length
z/OS lets OUTPUT access when an other program opened in for reading only (the new MOD lock overwrites the existing SHR lock)
EXAMPLE FOR OPENING AND CLOSING FILE:
The READ is for getting a record from a file, and placing the data into the corresponding record variable.
Works in:
INPUT mode
I-O mode
In SEQUENTIAL files, and INDEXED or RELATIVE files opened in sequential mode:
moves the record pointer 1 record forward, reads the pointed record
in case after moving the pointer the file end is reached, the flow steps into the AT END branch
In INDEXED files in opened in DYNAMIC or RANDOM mode:
the KEY IS clause defines the index which marks the needed record
moves the pointer to the record with the given index
if the index was not found, the flow steps into the INVALID KEY branch
In RELATIVE files in opened in DYNAMIC or RANDOM mode:
the RECORD NUMBER IS clause defines the record number which marks the needed record
moves the pointer to the record with the given record number
if the index was not found, the flow steps into the INVALID RECORD NUMBER branch
EXAMPLE FOR READ:
The WRITE is for writing the content of a record variable to a file as record.
Works in:
OUTPUT mode
I-O mode
EXTEND mode
WRITE writes data using the record structure in its full size. That means WRITE does not follow the current values of the components but the full memory area occupied by the record. This means before consideration is needed wether the INITIALIZE instruction is needed before giving values to the elements of the record.
In SEQUENTIAL files, and INDEXED or RELATIVE files opened in sequential mode:
writes the new record at the end of the file (append)
places the pointer after the written record (equals with the end of the file)
in case the process was unsuccessful, the flow steps into the INVALID KEY branch (necessary)
in case the process was successful, the flow steps into the NOT INVALID KEY branch (optional)
In INDEXED files in opened in DYNAMIC or RANDOM mode:
writes the structure to a new file record, based on the key field of the record variable
places the pointer after the written record
does not read the written record back
in case the key already exists, throws an error (unique key)
in case the process was unsuccessful, the flow steps into the INVALID KEY branch (necessary)
in case the process was successful, the flow steps into the NOT INVALID KEY branch (optional)
In RELATIVE files in opened in DYNAMIC or RANDOM mode:
writes the structure to a new file record, based on the record number field of the record variable
places the pointer after the written record
does not read the written record back
the record slot corresponding to the record number must be free, or throws an error
in case the process was unsuccessful, the flow steps into the INVALID KEY branch (obligatory)
in case the process was successful, the flow steps into the NOT INVALID KEY branch (optional)
In the background in case of INDEXED file, the key will be placed into the right place in the index, and the record will be placed in the CI.
EXAMPLE FOR WRITE:
The REWRITE is for modifying an existing file record with the content of a record variable.
Works in:
I-O mode
REWRITE writes data using the record structure in its full size. That means WRITE does not follow the current values of the components but the full memory area occupied by the record. This means before consideration is needed wether the INITIALIZE instruction is needed before giving values to the elements of the record.
In SEQUENTIAL files, and INDEXED or RELATIVE files opened in sequential mode:
it does not work, raises an error
In INDEXED files in opened in DYNAMIC or RANDOM mode:
works only if there already was at least 1 READ after opening the file
the previous READ moves the record pointer to the needed position
uses the record variable which received data via the recent READ but (obviously) has modified data
the key field of the record must not be changed
it does not move the record pointer during the modification process
the length of the record can not be larger than the original (KSDS fix/variable rules)
in case the record modification was unsuccessful, the flow steps into the INVALID KEY branch (obligatory)
in case the record modification was successful, the flow steps into the NOT INVALID KEY branch (optional)
In RELATIVE files in opened in DYNAMIC or RANDOM mode:
works only if there already was at least 1 READ after opening the file
the previous READ moves the record pointer to the needed position
uses the record variable which received data via the recent READ but (obviously) has modified data
the record number field of the record can be changed (avoid conflicts)
it does not move the record pointer during the modification process
the length of the record can not be larger than the original (RRDS fix/variable rules)
in case the record modification was unsuccessful, the flow steps into the INVALID RECORD NUMBER branch (obligatory)
in case the record modification was successful, the flow steps into the NOT INVALID RECORD NUMBER branch (optional)
In the background, as per the structure of the INDEXED files (header-key-data per record), the data part will be modified only. In case the key field was modified, the index layer of the file would be comprimised.
Similarly, in case of RELATIVE files, the record number identifies the exact slot, modifying the record number would direct the record to another slot, and compromise the data consistency.
EXAMPLE FOR REWRITE:
The DELETE is for deleting an existing file record.
Works in:
I-O mode
In SEQUENTIAL files, and INDEXED or RELATIVE files opened in sequential mode:
it does not work, raises an error (see alternative algorithm below)
In INDEXED files in opened in DYNAMIC or RANDOM mode:
works only if there already was at least 1 READ after opening the file
the previous READ moves the record pointer to the needed position
after deletion the pointer will point to the next record
due to unique keys, the key of the deleted record will be released
in case the record deletion was unsuccessful, the flow steps into the INVALID KEY branch (obligatory)
In the background, as per the structure of the INDEXED files, the area of the deleted record will be added to the CI (header-key-data-...-header-key-data-free_space-header-key-data-...-free_space-CI_control_area); the re-organization of the CA happens later (REORG).
In SEQUENTIAL files, the write, rewrite and deletion processes are:
open the source file in INPUT mode
create a new file in OUTPUT mode
launch an iteration which goes through all records in the source file
write the actual record to the new file but
write the new or the rewrote (modified) record when necessary, and
leave the record which is to be deleted
close the files
delete the source file and rename the new file if necessary
EXAMPLE FOR DELETE:
In VSAM KSDS files, evolved navigation techniques are:
range scan
key-based navigation
For these techniques, three main instructions are:
START (positioning)
READ NEXT/PREVIOUS (reading)
Work in:
INPUT mode
I-O mode
START:
filename (logical name)
KEY IS (positioning method)
INVALID KEY (what to do if key was not found)
NOT INVALID KEY (what to do if key was found)
KEY IS:
< (right before the key)
<= (the key or right before of that)
= (on the key)
>= (the key or right after that)
> (right after the key)
The result of the START is undeterminastic; the pointer which should mark the position of the record will point around the record. The READ type (NEXT/PREVIOUS) afterward will determine which pointer position will be used:
in case of forward direction afterward, it will point into the header of the record (before the found record)
in case of backward direction afterward, it will point into the header of the next record (after the found record)
Because upon executing the START, the algorithm does not know in which direction the READ process will go, the position coming from the START is undeterminastic: it prepares for READING in both directions.
EXAMPLE FOR START:
READ NEXT/PREVIOUS:
filename (logical)
NEXT RECORD (read the next record after the position)
PREVIOUS RECORD (read the previous record before the position)
AT END (what to do if there is no more record after reading the last one, or when the START did not find a key beforehand; logically obligatory)
NOT AT END (what to do if there are another record after reading the last one; logically optional)
The READ NEXT without START starts from the first record.
The READ PREVIOUS works only with KSDS and RRDS (indexed and relative) due to having backward connection between keys.
The READ reads the pointed record, then moves the pointer onto the next record (forward direction, NEXT) or the previous record (backward or reversed direction, PREVIOUS).
Upon moving the pointer, if there is another record, the flow steps into the NOT AT END branch.
If the READ can not move the pointer on the next (or previous) record (the new position would hit the end or the beginning of the file), the flow steps into the AT END branch.
The purpose of the RECORD word is to increase verbality, using it is fully optional.
EXAMPLE FOR READ NEXT/PREVIOUS:
EXAMPLE FOR RANDOM ACCESS OF A RECORD:
EXAMPLE FOR FORWARD SCAN FROM GIVEN KEY:
EXAMPLE FOR REVERSE SCAN FROM GIVEN KEY:
EXAMPLE FOR FOUND-FLAG, END-OF-FILE-FLAG:
After every I/O operation, it is advised to check the file-status. The WS-FILE-STATUS is the success flag of the operation, if the correct definitions exist, COBOL will change its value after every file operation.
Steps of definition:
FILE-CONTROL SECTION, physical-logical file declaration, status variable in FILE STATUS clause
WORKING-STORAGE SECTION, status variable declaration
The received status depends on the type of the physical storage:
PS, PDS, GDG members, QSAM
VSAM (KSDS, ESDS, RRDS)
Practical code is that in case a file operation fails, the code exits after writing a log about the found problem.
Also, before exiting it is advised to close all opened files. That leads to having a separate section or paragraph at the end of the PROCEDURE DIVISION with all the CLOSE statements.
EXAMPLE FOR TESTING THE WS-FILE-STATUS:
Usual coding pattern is that the record processing part is organized into a subroutine for cleaner and simplier code.
In such case the record by its variable name must be sent and received.
EXAMPLE FOR SEQUENTIAL FILE PROCESS (MAIN.CBL):
EXAMPLE FOR SUBROUTINE PROCESSOR (PROCESS-CUST.CBL):
EXAMPLE FOR INDEXED FILE PROCESS (IDXTEST.CBL):
EXAMPLE FOR RELATIVE (RECORD NUMBER) FILE PROCESS (RRDSTEST.CBL):