Direct File Access

Rexx provides several ways for you to read records of a file directly (that is, in random order). The following example, direct&per;cmd, shows several cases that illustrate some of your options.

direct&per;cmd opens a file for both reading and writing, which is indicated by the BOTH argument of the OPEN method. The REPLACE argument of the OPEN method causes any existing direct.dat file to be replaced.

The OPEN method also has the arguments BINARY and RECLENGTH, which are useful for direct file access.

The BINARY argument opens the stream in binary mode, which means that line-end characters are ignored. Binary mode is useful if you want to process binary data using line methods. It is easier to use line methods for direct access. With line methods, you can search a position in a file using line numbers. With character methods, you must calculate the character displacement of the file.

The RECLENGTH argument defines a record length of 50 for the file. It enables you to use line methods in a binary-mode stream. Because Rexx now knows how long each record is, it can calculate the displacement of the file for a given record number and read the record directly.


direct&per;cmd
/* DIRECT.CMD - demonstration of direct file access */
db=.stream~new("direct.dat")
db~open("both replace binary reclength 50")
/* Write three records of 50 bytes each using LINEOUT */
db~lineout("Cole, Gary: Blue")
db~lineout("McGuire, Rick: Red")
db~lineout("Pritko, Steve: Red. Oops.. I mean blue!")
/* Case 1: Read the records in order using LINEIN. */
say "Case 1: Sequential reads with LINEIN..."
do i=1 to 3
say db~linein
end
say "Press Enter to continue"; parse pull resp
/* Case 2: Read records in random order using LINEIN */
say "Case 2: Random reads with LINEIN..."
do i=1 to 5
lineno=random(1,3)
say "Record" lineno "=" db~linein(lineno)
end
say "Press Enter to continue"; parse pull resp
/* Case 3: Read entire file with CHARIN */
say "Case 3: Read entire file with a single CHARIN..."
say db~charin(1,150)
say "Press Enter to continue"; parse pull resp
/* Case 4: Read file sequentially with CHARIN */
say "Case 4: Sequential reads with CHARIN..."
db~seek(1 read) /* Reposition read pointer */
do i=1 to 3
say db~charin(,50)
end
say "Press Enter to continue"; parse pull resp
/* Case 5: Read records in random order with CHARIN */
say "Case 5: Random reads with CHARIN..."
do i=1 to 5
lineno=random(1,3)
charno=((lineno-1)*50)+1
say "Record" lineno "Character" charno "=" db~charin(charno,50)
end
say "Press Enter to continue"; parse pull resp
/* Case 6: Write records in random order with LINEOUT */
say "Case 6: Replace record 2 with LINEOUT"
db~lineout("This should replace line 2",2)
do i=1 to 3
say db~linein(i)
end
say "Press Enter to continue"; parse pull resp
/* Case 7: Write records in random order with CHAROUT */
say "Case 7: Replace record 2 with CHARIN..."
db~charout("New record 2 from CHAROUT"~left(50,"."),51)
db~seek(1 read) /* Reposition read pointer */
do i=1 to 3
say db~charin(,50)
end
say "Press Enter to continue"; parse pull resp
db~close

After opening the file, direct&per;cmd writes three records using LINEOUT. The records are not padded to 50 characters, Rexx itself handles that. Because the file is opened in binary mode, Rexx does not write line-end characters at the end of each line. It only writes the strings one after another to the stream.

In Case 1, the LINEIN method is used to read the file. Because the file is open in binary mode, LINEIN does not look for line-end characters to mark the end of a line. Instead, it relies on the record length that you specify on open. In fact, if there were a carriage-return or line-feed sequence of the line, Rexx would return those characters to your program.

Case 2 demonstrates how to read the file in random order. In this case, the RANDOM function is used to choose a record to be retrieved. Then the desired record number is specified as an argument on LINEIN. Note that records are numbered starting from 1, not from 0. Because the file is opened in binary mode, Rexx does not look for line-end characters. It uses the RECLENGTH value to determine where to begin reading. The LINEIN method can, therefore, retrieve a line directly, without having to scan through the file counting line-end characters.

Case 3 proves that no line-end characters exist in the file. The CHARIN method reads the entire file. SAY displays the returned string as one long string. If Rexx inserted line-end characters, each record would be displayed on a separate line.

Case 4 shows how to read the binary mode file sequentially using CHARIN. But before reading the file, the read pointer must be reset to the beginning of the file. (Case 3 leaves the read pointer at the end of the file.) The SEEK method resets the read pointer to character 1, which is the beginning of the file. As with lines, Rexx numbers characters starting with 1, not 0. Position 1 is the first character of the file.

By default, the number specified with SEEK refers to a character position. You can also search by line number or by offsets. SEEK allows offsets from the current read or write position (a relative position), or from the beginning or ending of the file (an absolute position). If you prefer typing longer method names, you can use POSITION as a synonym for SEEK.

In the loop of Case 4, the first argument on CHARIN is omitted. The first argument tells where to position the read pointer. If it is omitted, Rexx automatically advances the read pointer based on the number of characters you are reading.

Case 5 demonstrates how to read records in random order with CHARIN. In the loop, a random record number is selected and assigned to the variable lineno. This record number is then converted to a character number, which can be used to specify the read position on CHARIN. Compare Case 5 with Case 2. In Case 2, which uses line methods, it is not necessary to perform a calculation, you just request the record you want.

Cases 6 and 7 write records in random order. Case 6 uses LINEOUT, while Case 7 uses CHAROUT. Because the file is opened in binary mode, LINEOUT does not write line-end characters. You can write over a line by specifying a line number. With CHAROUT, you need to calculate the character position of the line to be replaced. Unlike LINEOUT, you need to ensure that the string being written with CHAROUT is padded to the appropriate record length. Otherwise, part of the record being replaced remains in the file.

Consequently, for random reading of files with fixed length records, line methods are often the better choice. However, one limitation of the line methods is that you cannot use them to write sparse records. That is, if a file already has 200 records, you can use LINEOUT to write record 201, but you cannot use LINEOUT to write record 300. With CHAROUT, however, you can open a new file and start writing at character position 5000 if you choose.