read, reade, readp and readpe return records one at a time, in key order or in the reverse of it. This page covers their syntax, the loops that end correctly, what makes %eof come on, what to do after end of file, and how record locks behave when you read an update file.
It is a focused page. The short entry for each file operation is in the RPGLE File I/O Opcodes Reference. What %eof and the other result functions mean is defined in the RPGLE File and Error BIFs Reference, and reading one record by key is in the RPGLE CHAIN Opcode Reference. The loop statements themselves are explained in the RPGLE DOW Loops lesson.
The examples are free-form RPGLE. They use a keyed file with the key fields CUSTKEY and ORDNO, which holds three records: C0001 / 1, C0001 / 2 and C0002 / 3.
dcl-f ordWork keyed usage(*update) extfile('*LIBL/ORDERW') rename(ORDERW : ordRec);
dcl-ds keyDs likerec(ordRec : *key);
dcl-s records int(10);
The four operations
read{(EN)} name {data-structure};
reade{(ENHMR)} search-arg or *key name {data-structure};
readp{(EN)} name {data-structure};
readpe{(ENHMR)} search-arg or *key name {data-structure};
| Opcode | Direction | Returns the record when | %eof comes on when |
|---|---|---|---|
read | Forward | Always, while records remain | There is no next record |
reade | Forward | The key equals the search argument | The key differs, or the file ends |
readp | Backward | Always, while records remain | There is no prior record |
readpe | Backward | The key equals the search argument | The key differs, or the file starts |
After readp and readpe, %eof means the beginning of the file, the old BOF indicator, not the end. A key that does not match is not an error. It is the normal way a reade loop ends, and the record that did not match is not returned.
| Part | Meaning |
|---|---|
name | The file name, or for an externally described file the record format name |
data-structure | Optional. Reads the record into this data structure instead of the file’s own fields |
search-arg | A field, literal or constant, a list of values, or %kds with a data structure. Free-form code must give a search argument or *key |
*key | Compare the full key of the next record with the full key of the current record |
(E) | Errors are not fatal. Test %error afterwards |
(N) | Read without locking the record. For an update file only |
Read a file to the end
Read once before the loop and again at the end of the loop body, so that %eof is tested after every read and the loop never processes a record twice or a missing one.
records = 0;
setll *start ordWork;
read ordWork;
dow not %eof(ordWork);
records += 1;
read ordWork;
enddo; // records is 3
The same loop can test at the bottom with dou. Then the record is only used when the read succeeded.
records = 0;
setll *start ordWork;
dou %eof(ordWork);
read ordWork;
if not %eof(ordWork);
records += 1;
endif;
enddo; // records is 3
Do not test %eof before the first read. It reflects the last file operation, not the next one. Do not use %found after a read. It is not the test for read.
Read one key with READE
reade returns the next record only if its key equals the search argument. Use setll first, so that the file is positioned at the start of the key you want. The loop ends when the key changes as well as at the end of the file.
records = 0;
keyDs.CUSTKEY = 'C0001';
setll %kds(keyDs : 1) ordWork;
reade %kds(keyDs : 1) ordWork;
dow not %eof(ordWork);
records += 1;
reade %kds(keyDs : 1) ordWork;
enddo; // records is 2
With %kds(keyDs : 1) only CUSTKEY is compared, so both C0001 records are returned. Name every key field to match one exact record.
A reade that gives a search argument and comes straight after opening the file or after end of file compares the first record of the file, which is why the setll matters. *key has no such start. It compares the next record with the current one, so it needs a record that has already been read, and IBM describes an error for a reade with no search argument straight after open or end of file. Use *key only after a successful read.
Loop over several keys
Put the single-key loop in a procedure and call it for each key.
dcl-proc countCustomer;
dcl-pi *n int(10);
cust char(5) const;
end-pi;
dcl-ds custKey likerec(ordRec : *key);
dcl-s n int(10) inz(0);
custKey.CUSTKEY = cust;
setll %kds(custKey : 1) ordWork;
reade %kds(custKey : 1) ordWork;
dow not %eof(ordWork);
n += 1;
reade %kds(custKey : 1) ordWork;
enddo;
return n;
end-proc;
records = countCustomer('C0001') + countCustomer('C0002'); // 2 + 1, so 3
Each call positions the file again, so the order of the calls does not matter.
Read backwards with READP and READPE
readp returns the previous record, so start from the end. setll *end positions at the end of the file, and the first readp then returns the last record.
records = 0;
setll *end ordWork;
readp ordWork;
dow not %eof(ordWork);
records += 1;
readp ordWork;
enddo; // records is 3, from C0002 / 3 down to C0001 / 1
readpe is the backward version of reade. To read one key from its last record to its first, position after the key with setgt, then read backwards while the key matches.
records = 0;
keyDs.CUSTKEY = 'C0001';
setgt %kds(keyDs : 1) ordWork;
readpe %kds(keyDs : 1) ordWork;
dow not %eof(ordWork);
records += 1;
readpe %kds(keyDs : 1) ordWork;
enddo; // records is 2: C0001 / 2, then C0001 / 1
The positioning operations are in the RPGLE SETLL and SETGT Opcode Reference.
After end of file
Once %eof is on, the file is not positioned. IBM says to reposition it with chain, setll or setgt before any further read, and a read that follows without repositioning reports end of file again. The same applies after any other error on the read, except a record-lock error, described below.
read ordWork; // end of file again: the file was not repositioned
setll *start ordWork;
read ordWork; // C0001 / 1, the first record
Reading into a data structure and testing for errors
Name a data structure to read the record into it. For an externally described file, define it with likerec or extname. Add (e) to handle real file errors yourself.
dcl-ds ordData likerec(ordRec : *input);
setll *start ordWork;
read(e) ordWork ordData;
if %error;
// the read failed: handle it
elseif not %eof(ordWork);
// ordData.ORDNO holds the order number
endif;
Code either the (e) extender or the ER indicator, but not both. Older code puts EOF in positions 75 to 76, which is %eof. Fixed-format conversion is in the Fixed-Format to Free-Format Opcode Mapping.
Record locks when reading
On a file declared for update, each read locks the record it returns, unless you add (n).
read(n) ordWork; // read without a lock
An input-only file does not lock records, and the (n) extender is for update files. A record that is locked by another job makes the read fail with status 1218, and the file stays positioned at the locked record. The next read tries that record again, so you can wait and retry without repositioning. Do not hold a lock while waiting for a user.
IBM notes that on an update file reade can occasionally wait for a temporary lock on a record whose key does not match, and release it when it sees the key differs. The causes include a current record whose key differs from the search argument, null-capable fields and end-of-file delay. Add (n) when you do not intend to update.
A record you read with (n), or a read that failed, is not locked, so update cannot follow it. Changing and deleting records is covered in the RPGLE UPDATE, WRITE and DELETE Opcode Reference.
Common mistakes
- Testing
%eofbefore the first read, or reading only once, so the loop skips or repeats a record. - Reading again after end of file without repositioning the file.
- Testing
%foundafter a read. Use%eof. - Calling
readewithoutsetll, so the position is wherever the last operation left it. - Using
*keystraight after open or end of file. - Reading an update file with locks when
(n)would do. - Treating
%eofafterreadpas end of file. It is the beginning of the file.
FAQ
What does %EOF mean after READE?
Either the key of the next record differs from the search argument, or the file ended. Both end the loop, and the record that did not match is not returned.
Do I need to reposition the file after end of file?
Yes. Use setll, setgt or chain before reading again.
How do I read the last record of a key first?
Use setgt with the key to position after the group, then readpe with the same key to read the group from its last record to its first.
Summary
readandreadpreturn every record in one direction, andreadeandreadpestop when the key changes. Test%eofafter each one.- Read once before the loop and again at the end of the loop body.
- Position first with
setll,setgtorchain, and reposition after end of file. - On an update file each read locks the record,
(n)reads without a lock, and a lock failure with status 1218 leaves the file at the locked record. - For the other file operations see the RPGLE File I/O Opcodes Reference.