HP OpenVMS Systems Documentation

Content starts here

HP BASIC for OpenVMS
User Manual


Previous Contents Index

13.6.10 Accessing Records by Record File Address

A Record File Address (RFA) uniquely specifies a record in a file. Accessing records by RFA is therefore more efficient and faster than other forms of random record access.1

Because an RFA requires six bytes of storage, BASIC has a special data type, RFA, that denotes variables that contain RFA information. Variables of data type RFA can be used only with the I/O statements and functions that use RFA information, and in comparison and assignment statements. You cannot print these variables or use them in any arithmetic operation. However, you can compare RFA variables using the equal to (=) and not equal to (<>) relational operators.

You cannot create named constants of the RFA data type. However, you can assign values from one RFA variable to another, and you can use RFA variables as parameters.

Accessing a record by RFA requires the following steps:

  1. Explicitly declare the variable or array of data type RFA to hold the address.
  2. Assign the address to the variable or array element. You can do this either with the GETRFA function, or by reading a file of RFAs generated by previous GETRFA functions or by the VMS Sort Utility.
  3. Specify the variable in the RFA clause of a GET or FIND statement.

The GETRFA function returns the RFA of the last record accessed on a channel. Therefore, you must access a record in the file with a GET, FIND, or PUT statement before using the GETRFA function. Otherwise, GETRFA returns a zero, which is an invalid RFA.

The following example declares an array of type RFA containing 100 elements. After each PUT operation, the RFA of the record is assigned to an element of the array. Once the RFA information is assigned to a program variable or array element, you can use the RFA clause on a GET or FIND statement to retrieve the record.


DECLARE RFA R_array(1 TO 100)
DECLARE LONG I
MAP (XYZ) STRING A = 80
OPEN "TEST.DAT" FOR OUTPUT AS FILE #1,     &
      SEQUENTIAL, MAP XYZ
FOR I = 1% TO 100%
   .
   .
   .
    PUT #1
    R_array(I) = GETRFA(1%)
NEXT I

You can use the RFA clause on GET or FIND statements for any file organization; the only restriction is that the file must reside on a disk that is accessible to the node that is executing the program. An RFA value is only valid for the life of a specific version of a file. If a new version of a file is created, the RFA values might change. If you attempt to access a record with an invalid RFA value, HP BASIC signals a run-time error.

The following example continues the previous one. It randomly retrieves the records in a sequential file by using RFAs stored in the array.


DECLARE RFA R_array(1% TO 100%)
DECLARE LONG I
MAP (XYZ) STRING A = 80
OPEN "TEST.DAT" FOR OUTPUT AS FILE #1,     &
      SEQUENTIAL, MAP XYZ
FOR I = 1% TO 100%
   .
   .
   .
    PUT #1
    R_array(I) = GETRFA(1%)
NEXT I
WHILE -1%
    PRINT "Which record would you like to see";
    INPUT "(type a carriage return to exit)";Rec_num%
    EXIT PROGRAM IF Rec_num% = 0%
    GET #1, RFA R_array(Rec_num%)
    PRINT A
NEXT

13.6.11 Transferring Data to Terminal-Format Files

The PRINT # statement transfers program data to a terminal-format file. In the following example, the INPUT statements prompt the user for three values: S_name$, Area$, and Quantity%. Once these values are entered, the PRINT # statement writes these values to a terminal-format file that is open on channel #4.


FOR I% = 1% TO 10%
    INPUT "Name of salesperson":S_name$
    INPUT "Sales district";Area$
    INPUT "Quantity sold";Quantity%
    PRINT #4%, S_name$, Area$, Quantity%
NEXT I%

If you do not specify an output list in the PRINT # statement, a blank line is written to the terminal-format file. A PRINT statement without a channel number transfers program data to a terminal. See Chapter 5 for more information.

13.6.12 Resetting the File Position

The RESTORE # statement resets the current record pointer to the beginning of the file; it does not change the file. RESET # is a synonym for RESTORE. For example:


RESTORE #3%, KEY #2%
RESET #3%

The RESTORE # statement restores the file in terms of the second alternate key. The RESET # statement restores the file in terms of the primary key.

The RESTORE # statement can be used by all RMS file organizations. RESTORE without a channel number resets the data pointer for READ and DATA statements but does not affect any files.

13.6.13 Truncating Files

The SCRATCH statement is valid only on sequential files. Although you cannot delete individual records from a sequential file, you can delete all records starting with the current record through to the end of the file. In order to do this, you must first specify ACCESS SCRATCH when you open the file.

To truncate the file, locate the first record to be deleted. Once the current record pointer points to this record, execute the SCRATCH statement. The following program locates the thirty-third record and truncates the file beginning with that record.


OPEN "MMM.DAT" AS FILE #2%,            &
      SEQUENTIAL FIXED, ACCESS SCRATCH

first_bad_record = 33%

FIND #2%, RECORD first_bad_record
SCRATCH #2%
CLOSE #2%
END

SCRATCH does not change the physical size of the file; it reduces the amount of information contained in the file. (You can use the DCL command SET FILE/TRUNCATE to truncate the excess file space.) Therefore, you can write records with the PUT statement immediately after a SCRATCH operation.

13.6.14 Renaming Files

If the security constraints permit, you can change the name or directory of a file with the NAME...AS statement. For example:


NAME "MONEY.DAT" AS "ACCOUNTS.DAT"

This statement changes the name of the file MONEY.DAT to ACCOUNTS.DAT.

Note

The NAME...AS statement can change only the name and directory of a file; it cannot be used to change the device name.

You must always include an output file type because there is no default. If you use the NAME...AS statement on an open file, the new name does not take effect until you close the file.

13.6.15 Closing Files and Ending I/O

All programs should close files before the program terminates. However, files are automatically closed in the following situations:

  • At an END, END PROGRAM, or EXIT PROGRAM statement
  • When it completes the last statement in the program if no END statement exists
  • While executing a CHAIN statement

Files are not closed after executing a STOP, END SUB, END FUNCTION, or END PICTURE statement.

The CLOSE statement closes files and disassociates these files and their buffers from the channel numbers. If the file is a magnetic tape device and the data is written to a tape, CLOSE writes trailer labels at the end of the file. The following is an example of the CLOSE statement:


CLOSE #1%
B% = 4%
CLOSE #2%, B%, 7%
CLOSE I% FOR I% = 1% TO 20%

13.6.16 Deleting Files

If the security constraints permit, you can delete a file with the KILL statement. For example:


KILL "TEST.DAT"

This statement deletes the file named TEST.DAT. Note that this statement deletes only the most current version of the file. Do not omit the file type, because there is no default. You can delete only one file at a time; to delete all versions of a file matching a file specification, use the Run-Time Library routine LIB$DELETE_FILE.

You can delete a file that is currently being accessed by other users; however, the file is not deleted until all users have closed it. You cannot open or access a file once you have deleted it.

Note

1 Record File Addresses do not exist for terminal-format files.

13.7 File-Related Functions

The following built-in functions are provided for finding:

  • The characteristics of the last file opened (FSP$)
  • The number of bytes moved in the last I/O operation (RECOUNT)
  • The file status (STATUS, VMSSTATUS, and RMSSTATUS)

These functions are discussed in the following sections.

13.7.1 FSP$ Function

If you do not know the organization of a file, you can find out by opening the file for input with the ORGANIZATION UNDEFINED and RECORDTYPE ANY clauses. Your program can then use the FSP$ function to determine the characteristics of that file. Your program must execute FSP$ immediately after the OPEN FOR INPUT statement. For example:


RECORD FSP_data
       VARIANT
       CASE
          BYTE Org
          BYTE Rat
          WORD Max_record_size
          LONG File_size
          WORD Bucketsize_blocksize
          WORD Num_keys
          LONG Max_record_number
       CASE
          STRING Ret_string = 16
       END VARIANT
END RECORD

DECLARE FSP_data File_chars

OPEN "FIL.DAT" FOR INPUT AS FILE #1%,              &
    ORGANIZATION UNDEFINED,                        &
    RECORDTYPE ANY, ACCESS READ
File_chars::Ret_string = FSP$(1%)

The following list explains the above example:

  • Rat returns the low byte that is the RMS record attributes (RAT) field.
  • Org returns the high byte that is the RMS organization (ORG) field.
  • Max_record_size returns the RMS maximum record size (MRS) field.
  • File_size returns the RMS allocation quantity (ALQ) field.
  • Bucketsize_blocksize returns the RMS bucket size (BKS) field for disk files or the RMS block size (BLS) field for magnetic tape files.
  • Num_keys returns the number of keys.
  • Max_record_number returns the RMS maximum record number (MRN) field if the file is a relative file.

Note that FSP$ returns zeros in bytes 9 to 12. For more information, see the OpenVMS Record Management Services Reference Manual.

13.7.2 RECOUNT Function

Read operations can transfer varying amounts of data. The system variable RECOUNT contains the number of characters (bytes) read after each read operation.

After a read operation from your terminal, RECOUNT contains the number of characters transferred, including the line terminator. After accessing a record, RECOUNT contains the number of characters in the record.

RECOUNT is reset by every read operation on any channel, including the controlling terminal. Therefore, if you need to use the value of RECOUNT, copy it to another variable before executing another read operation. RECOUNT is undefined if an error occurs during a read operation.

RECOUNT is often used as the argument to the COUNT clause in the UPDATE or PUT statement for variable-length files. The following sequence of statements ensures that the output record on channel #5 is the same length as the input record on channel #4:


GET #4%
bytes_read% =  RECOUNT
   .
   .
   .
PUT #5%, COUNT bytes_read%

13.7.3 STATUS, VMSSTATUS, and RMSSTATUS Functions

The STATUS function accesses the status longword that contains characteristics of the last opened file. If an error occurs during an input operation, the value of STATUS is undefined. If an error does not occur, the six low-order bits of the returned value contain information about the type of device accessed by the last input operation. These bits correspond to the following devices:

  • If bit 0 is set, the device type is a record-oriented device.
  • If bit 1 is set, the device type is a carriage control device.
  • If bit 2 is set, the device type is a terminal.
  • If bit 3 is set, the device type is a directory oriented device.
  • If bit 4 is set, the device type is a single directory device.
  • If bit 5 is set, the device type is a sequential block-oriented device (magnetic tape or TK50).

Both the VMSSTATUS and RMSSTATUS functions are used to determine which non-BASIC error caused a resulting BASIC error. In particular, VMSSTATUS can be used for any non-BASIC errors, while RMSSTATUS is used specifically for RMS errors. For more information about these functions, see Chapter 15 and the HP BASIC for OpenVMS Reference Manual.

13.8 OPEN Statement Options

This section explains the OPEN statement keywords that enable you to control how a file is created or opened. These keywords are:

BUCKETSIZE
BUFFER
CONNECT
CONTIGUOUS
DEFAULTNAME
EXTENDSIZE
FILESIZE
NOSPAN
RECORDTYPE
TEMPORARY
USEROPEN
WINDOWSIZE

13.8.1 BUCKETSIZE Clause

The BUCKETSIZE clause applies only to relative and indexed files. A bucket is a logical storage structure that RMS uses to build and maintain relative and indexed files on disk devices. A bucket consists of one or more disk blocks. The default bucket size is the record size rounded up to a block boundary. Although RMS defines the bucket size in terms of disk blocks, the BUCKETSIZE clause specifies the number of records a bucket contains. For example:


OPEN  "STOCK_DATA.DAT" FOR OUTPUT AS FILE #1%,           &
      ORGANIZATION RELATIVE FIXED, BUCKETSIZE 12%

This example specifies a bucket containing approximately 12 records. RMS reads in entire buckets into the I/O buffer at once, and a GET statement transfers one record from the I/O buffer to your program's record buffer.

When you open an existing relative or indexed file and specify a bucket size other than that originally assigned to the file, BASIC signals the error, "File attributes not matched" (ERR=160).

Records cannot span bucket boundaries. Therefore, when you specify a bucket size in your program, you must consider the size of the largest record in the file. Note that a bucket must contain at least one record. Buckets in both relative and indexed files contain information in addition to the records stored in the bucket. You should take this into consideration.

There are two ways to establish the number of blocks in a bucket. The first is to use the default. The second is to specify the approximate number of records you want in each bucket. A bucket size based on that number is then calculated.

The default bucket size assigned to relative and indexed files is as small as possible. A small bucket size, however, is rarely desirable.

A default bucket size is selected depending on the:

  • Record length
  • File organization (relative or indexed)
  • Record format

If you do not define the BUCKETSIZE clause in the OPEN statement, BASIC does the following:

  • Assumes that there is a minimum of one record in the bucket
  • Calculates a size
  • Assigns the appropriate number of blocks

Note that when you specify a bucket size for files in your program, you must keep in mind the space versus speed tradeoffs. A large bucket size increases file processing speed because a greater amount of data is available in memory at one time; however, it also increases the memory space needed for buffer allocation and the processing time required to search the bucket. Conversely, a small bucket size minimizes buffer requirements, but increases the number of accesses to the storage device, thereby decreasing the speed of operations.

It is recommended that you use the DCL command EDIT/FDL to design files used in production applications where performance is a concern.

13.8.2 BUFFER Clause

The BUFFER clause applies to disk files of any organization. In the case of sequential files, the BUFFER clause sets the number of blocks read in on each disk access. For relative and indexed files, the BUFFER clause determines the number of I/O buffers that are allocated. In general, the OpenVMS operating system supplies adequate defaults for all file types; therefore, the BUFFER clause is rarely necessary.

You can specify up to 127 buffers as either a positive or a negative number:

  • If (0 < BUFFER < 127), RMS allocates enough space for the specified number of buckets.
  • If (-128 < BUFFER < 0), BASIC allocates the absolute value of the specified number of buffers.
  • If (BUFFER=0), BASIC allocates the process default for the particular file organization and device---this value is usually adequate.

13.8.3 CONNECT Clause

The CONNECT clause can be used only on indexed files. CONNECT lets you process different groups of records on different indexed keys or on the same key without incurring all of the RMS overhead of opening the same file more than once. For example, a program can read records in an indexed file sequentially by one key and randomly by another. Each stream is an independent, active series of record operations.


MAP (Indmap) WORD Emp_num,                     &
     STRING Emp_last_name = 20,                &
     SINGLE Salary,                            &
     STRING Wage_code = 2
OPEN "IND.DAT" FOR INPUT AS FILE #1%,          &
     ORGANIZATION INDEXED,                     &
     MAP Indmap,                               &
     PRIMARY KEY Emp_num,                      &
     ALTERNATE KEY Emp_last_name
   .
   .
   .
OPEN "IND.DAT" FOR INPUT AS FILE #2%           &
     ORGANIZATION INDEXED,                     &
     MAP Indmap,                               &
     CONNECT 1

The channel on which you open the file for the first time is called the parent. The CONNECT clause specifies another channel on which you access the same file; connected channels are called children. More than one OPEN statement can connect to the parent channel; however, you cannot connect to a channel that has already been connected to another channel.

Do not use the CONNECT clause when accessing files on remote DECnet nodes.

13.8.4 CONTIGUOUS Clause

A contiguous file with physically adjoining blocks minimizes disk searching and decreases file access time. Once the system knows where a contiguous file starts on the disk, it does not need to use as many retrieval pointers to locate the pieces of that file. Rather, it can access data by calculating the distance from the beginning of the file to the desired data. If there is not enough contiguous disk space, BASIC allocates as much contiguous space as possible. (For truly contiguous records, you must use the USEROPEN clause and set the CTG bit in the FAB FOP field---see the OpenVMS Record Management Services Reference Manual.)

Opening a file with both the FILESIZE and CONTIGUOUS clauses pre-extends the file contiguously or in as few disk extents as possible.

13.8.5 DEFAULTNAME Clause

The DEFAULTNAME clause in the OPEN statement lets you specify a default file specification for the file to be opened. It is valid with all file organizations. BASIC uses the DEFAULTNAME clause for any part of the file specification that is not explicitly supplied.


LINPUT "Next data file";Fil$
OPEN Fil$ FOR INPUT AS FILE #5%,       &
     ORGANIZATION SEQUENTIAL,          &
     DEFAULTNAME "USER$DEVICE:.DAT"

The DEFAULTNAME clause supplies default values for the device, directory, and file type portions of the file specification. Typing ABC in response to the Next data file? prompt causes BASIC to try to open USER$DEVICE:ABC.DAT.

BASIC uses the DEFAULTNAME values only if you do not supply those parts of the file specification appearing in the DEFAULTNAME clause. For example, if you type SYS$DEVICE:ABC in response to the prompt, BASIC tries to open SYS$DEVICE:ABC.DAT. In this case, SYS$DEVICE: overrides the device default in the DEFAULTNAME clause. Any part of the file specification still missing is filled in from the current default device and directory of the process.

13.8.6 EXTENDSIZE Clause

The EXTENDSIZE attribute determines how many disk blocks RMS adds to the file when the current allocation is exhausted. The EXTENDSIZE clause only has an effect when creating a file. You specify EXTENDSIZE as a number of blocks. For example:


OPEN "TSK.ORN" FOR OUTPUT AS FILE #2%,   &
      ORGANIZATION RELATIVE, EXTENDSIZE 128%

The EXTENDSIZE clause causes RMS to add 128 disk blocks whenever the current space allocation is exhausted and the file must be extended.

The value you specify must conform to the following requirements:

  • It must be specified when you create the file
  • It cannot exceed 65,535 disk blocks

If you specify zero, the extension size equals the RMS default value. The EXTENDSIZE value can be overridden for single OPEN operations.

13.8.7 FILESIZE Clause

With the FILESIZE attribute, you can allocate disk space for a file when you create it. The following statement allocates 50 blocks of disk space for the file VALUES.DAT:


OPEN "VALUES.DAT" FOR OUTPUT AS FILE #3%, FILESIZE 50%

Pre-extending a file has several advantages:

  • The system can create a complete directory structure for the file, instead of allocating and mapping additional disk blocks when needed.
  • You reserve the needed disk space for your application. This ensures that you do not run out of space when the program is running.
  • Pre-extension can make some of the file's disk blocks contiguous, especially when used with the CONTIGUOUS keyword.

Note that pre-extension can be a disadvantage if it allocates disk space needed by other users. The FILESIZE clause is ignored when HP BASIC opens an existing file.


Previous Next Contents Index