Input and output

This chapter describes Delphi’s standard (or built-in) input and output () procedures and functions. You'll find them in the System unit.

Table 13-1 Input and output procedures and functions

Append Opens an existing text file for appending.

AssignFile Assigns the name of an external file to a file variable.

BlockRead Reads one or more records from an untyped file. BlockWrite Writes one or more records into an untyped file. ChDir Changes the current directory.

CloseFile Closes an open file.

Eof Returns the end-of-file status of a file.

Eoln Returns the end-of-line status of a text file.

Erase Erases an external file.

FilePos Returns the current file position of a typed or untyped file.

FileSize Returns the current size of a file; not used for text files.

Flush Flushes the buffer of an output text file.

GetDir Returns the current directory of a specified drive.

IOResult Returns an integer value that is the status of the last I/O function performed.

MkDir Creates a subdirectory.

Read Reads one or more values from a file into one or more variables.

Readln Does what a Read does and then skips to the beginning of the next line in the text file.

Rename Renames an external file.

Reset Opens an existing file.

Rewrite Creates and opens a new file.

RmDir Removes an empty subdirectory.

Seek Moves the current position of a typed or untyped file to a specified component. Not used with text files.

SeekEof Returns the end-of-file status of a text file.

SeekEoln Returns the end-of-line status of a text file.

SetTextBuf Assigns an I/O buffer to a text file.

Truncate Truncates a typed or untyped file at the current file position.

Write Writes one or more values to a file.

Writeln Does the same as a Write, and then writes an end-of-line marker to the text file.

File input and output

An Object Pascal file variable is any variable whose type is a file type. There are three classes of Object Pascal files: typed, text, and untyped. The syntax for writing file types is given on page 21.

Before a file variable can be used, it must be associated with an external file through a call to the AssignFile procedure. An external file is typically a named disk file, but it can also be a device, such as the keyboard or the display. The external file stores the information written to the file or supplies the information read from the file.

Once the association with an external file is established, the file variable must be "opened" to prepare it for input or output. An existing file can be opened via the Reset procedure, and a new file can be created and opened via the Rewrite procedure. Text files opened with Reset are read-only and text files opened with Rewrite and Append are write-only. Typed files and untyped files always allow both reading and writing regardless of whether they were opened with Reset or Rewrite.

Every file is a linear sequence of components, each of which has the component type (or record type) of the file. Each component has a component number. The first component of a file is considered to be component zero.

Files are normally accessed sequentially; that is, when a component is read using the standard procedure Read or written using the standard procedure Write, the current file position moves to the next numerically ordered file component. Typed files and untyped files can also be accessed randomly, however, using the standard procedure Seek, which moves the current file position to a specified component. The standard functions FilePos and FileSize can be used to determine the current file position and the current file size.

When a program completes processing a file, the file must be closed using the standard procedure CloseFile. After a file is closed, its associated external file is updated. The file variable can then be associated with another external file.

By default, all calls to standard I/O procedures and functions are automatically checked for errors, and if an error occurs an exception is raised (or the program is terminated if exception handling is not enabled). This automatic checking can be turned on and off using the {$I+} and {$I-} compiler directives. When I/O checking is off--that is, when a procedure or function call is compiled in the {$I-} state--an I/O error doesn't cause an exception to be raised. To check the result of an I/O operation, you must call the standard function IOResult instead.

You must call the IOResult function to clear whatever error may have occurred, even if you aren't interested in the error. If you don't and {$I+} is the current state, the next I/O function call fails with the lingering IOResult error.

Text files

This section summarizes I/O using file variables of the standard type Text.

When a text file is opened, the external file is interpreted in a special way: It is considered to represent a sequence of characters formatted into lines, where each line is terminated by an end-of-line marker (a carriage-return character, possibly followed by a linefeed character). In Object Pascal, the type Text is distinct from the type file of Char.

For text files, there are special forms of Read and Write that let you read and write values that are not of type Char. Such values are automatically translated to and from their character representation. For example, Read(F, I), where I is a type Integer variable, reads a sequence of digits, interprets that sequence as a decimal integer, and stores it in I.

Object Pascal defines two standard text-file variables, Input and Output. The standard file variable Input is a read-only file associated with the operating system's standard input file (typically the keyboard). The standard file variable Output is a write-only file associated with the operating system's standard output file (typically the display):

AssignFile(Input, ''); Reset(Input); AssignFile(Output, ''); Rewrite(Output);

Because Windows doesn't directly support text-oriented I/O, the I/O files are unassigned in a Windows application, and any attempt to read or write to them will produce an I/O error. If a Windows application uses the WinCrt unit, however, Input and Output refer to a scrollable text window. WinCrt contains the complete control logic required to emulate a text screen in the Windows environment, and no Windows-specific programming is required in an application that uses WinCrt. See page 142 for more about the WinCrt unit.

Some of the standard I/O routines that work on text files don't need to have a file variable explicitly given as a parameter. If the file parameter is omitted, Input or Output is assumed by default, depending on whether the procedure or function is input- or output-oriented. For example, Read(X) corresponds to Read(Input, X) and Write(X) corresponds to Write(Output, X).

If you do specify a file when calling one of the input or output routines that work on text files, the file must be associated with an external file using AssignFile, and opened using Reset, Rewrite, or Append. An exception is raised if you pass a file that was opened with Reset to an output-oriented procedure or function. An exception is also raised if you pass a file that was opened with Rewrite or Append to an input- oriented procedure or function.

Untyped files

Untyped files are low-level I/O channels primarily used for direct access to any disk file regardless of type and structuring. An untyped file is declared with the word file and nothing more. For example,

var

DataFile: file;

For untyped files, the Reset and Rewrite procedures allow an extra parameter to specify the record size used in data transfers. For historical reasons, the default record size is 128 bytes. A record size of 1 is the only value that correctly reflects the exact size of any file (no partial records are possible when the record size is 1).

Except for Read and Write, all typed-file standard procedures and functions are also allowed on untyped files. Instead of Read and Write, two procedures called BlockRead and BlockWrite are used for high-speed data transfers.

Input and output with the WinCrt unit

The WinCrt unit implements a terminal-like text screen in a window. With WinCrt, you can easily create a Windows program that uses the Read, Readln, Write, and Writeln standard procedures to perform input and output operations. WinCrt contains the complete control logic required to emulate a text screen in the Windows environment. You don't need to write "Windows-specific" code if your program uses WinCrt.

Using the WinCrt unit

To use the WinCrt unit, simply include it in your program's uses clause, just as you would any other unit:

uses WinCrt;

By default, the Input and Output standard text files defined in the System unit are unassigned, and any Read, Readln, Write, or Writeln procedure call without a file variable causes a run-time error. But when a program uses the WinCrt unit, the initialization code of the unit assigns the Input and Output standard text files to refer to a window that emulates a text screen. It's as if the following statements are executed at the beginning of your program:

AssignCrt(Input); Reset(Input); AssignCrt(Output); Rewrite(Output);

When the first Read, Readln, Write, or Writeln call executes in the program, a CRT window opens on the Windows desktop. The default title of a CRT window is the full path of the program's .EXE file. When the program finishes (when control reaches the final end reserved word), the title of the CRT window is changed to "(Inactive nnnnn)", where nnnnn is the title of the window in its active state.

Even though the program has finished, the window stays up so that the user can examine the program's output. Just like any other Windows application, the program doesn't completely terminate until the user closes the window.

The InitWinCrt and DoneWinCrt routines give you greater control over the CRT window's life cycle. A call to InitWinCrt immediately creates the CRT window rather than waiting for the first call to Read, Readln, Write, or Writeln. Likewise, calling DoneWinCrt immediately destroys the CRT window instead of when the user closes it.

The CRT window is a scrollable panning window on a virtual text screen. The default dimensions of the virtual text screen are 80 columns by 25 lines, but the actual size of the CRT window may be less. If the size is less, the user can use the window's scroll bars or the cursor keys to move this panning window over the larger text screen. This is particularly useful for scrolling back to examine previously written text. By default, the panning window tracks the text screen cursor. In other words, the panning window automatically scrolls to ensure that the cursor is always visible. You can disable the autotracking feature by setting the AutoTracking variable to False.

The dimensions of the virtual text screen are determined by the ScreenSize variable. You can change the virtual screen dimensions by assigning new dimensions to ScreenSize before your program creates the CRT window. When the window is created, a screen buffer is allocated in dynamic memory. The size of this buffer is ScreenSize.X multiplied by ScreenSize.Y, and it can't be larger than 65,520 bytes. It's up to you to ensure that the values you assign to ScreenSize.X and ScreenSize.Y don't overflow this limit. If, for example, you assign 64 to ScreenSize.X, the largest allowable value for ScreenSize.Y is 1,023.

At any time while running a program that uses the WinCrt unit, the user can terminate the application by choosing the Close command on the CRT window's Control menu, double-clicking the Control-menu box, or pressing Alt+F4. The user can also press Ctrl+C or Ctrl+Break at any time to halt the application and force the window into its inactive state; you can disable these features by setting the CheckBreak variable to False at the beginning of the program.

Special characters

When writing to Output or a file that has been assigned to the CRT window, the following control characters have special meanings:

Table 13-2 Special characters in the WinCrt window

Char Name Description

#7

BELL

Emits a beep from the internal speaker.

#8

BS

Moves the cursor left one column and erases the character at that position. If the cursor is already at the left edge of the screen, nothing happens.

#10

LF

Moves the cursor down one line. If the cursor is already at the bottom of the virtual screen, the screen is scrolled up one line.

#13

CR

Returns the cursor to the left edge of the screen.

Line input

When your program reads from Input or a file that has been assigned to the CRT window, text is input one line at a time. The line is stored in the text file's internal buffer, and when variables are read, this buffer is used as the input source. When the buffer empties, a new line is read and stored in the buffer.

When entering lines in the CRT window, the user can use the Backspace key to delete the last character entered. Pressing Enter terminates the input line and stores an end-of-line marker (CR/LF) in the buffer. In addition, if the CheckEOF variable is set to True, a Ctrl+Z also terminates the input line and generates an end-of-file marker. CheckEOF is False by default.

To test keyboard status and input single characters under program control, use the

KeyPressed and ReadKey functions.

WinCrt procedures and functions

The following tables list the procedures and functions defined by the WinCrt unit.

Table 13-3 WinCrt procedures and functions

AssignCrt Associates a text file with the CRT window.

ClrEol Clears all the characters from the cursor position to the end of the line.

ClrScr Clears the screen and returns cursor to the upper left-hand corner.

CursorTo Moves the cursor to the given coordinates within the virtual screen. The origin coordinates are 0,0.

DoneWinCrt Destroys the CRT window.

GotoXY Moves the cursor to the given coordinates within the virtual screen. The origin coordinates are 1,1.

InitWinCrt Creates the CRT window.

KeyPressed Returns True if a key has been pressed on the keyboard.

ReadBuf Inputs a line from the CRT window.

ReadKey Reads a character from the keyboard.

ScrollTo Scrolls the CRT window to show a screen location.

TrackCursor Scrolls the CRT window to keep the cursor visible.

WhereX Returns the x-coordinate of the current cursor location. The origin coordinates are 1,1. WhereY Returns the y-coordinate of the current cursor location. The origin coordinates are 1,1. WriteBuf Writes a block of characters to the CRT window.

WriteChar Writes a single character to the CRT window.

WinCrt unit variables

The WinCrt unit declares several variables:

Table 13-4 WinCrt variables

WindowOrg Determines the initial location of the CRT window.

WindowSize Determines the initial size of the CRT window.

ScreenSize Determines the width and height in characters of the virtual screen within the CRT window.

Cursor Contains the current position of the cursor within the virtual screen. Cursor is 0,0 based.

Origin Contains the virtual screen coordinates of the character cell displayed in the upper left corner of the CRT window. Origin is 0,0 based.

InactiveTitle Points to a null-terminated string to use when constructing the title of an inactive CRT window.

AutoTracking Enables and disables the automatic scrolling of the window to keep the cursor visible.

CheckEOF Enables and disables the end-of-file character. CheckBreak Enables and disables user termination of an application. WindowTitle Determines the title of the CRT window.

Text-file device drivers

Object Pascal lets you define your own text-file device drivers for your Windows programs. A text-file device driver is a set of four functions that completely implement an interface between Object Pascal's file system and some device.

The four functions that define each device driver are Open, InOut, Flush, and Close.

The function header of each function is

function DeviceFunc(var F: TTextRec): Integer;

where TTextRec is the text-file record-type defined on page 166. Each function must be compiled in the {$F+} state to force it to use the far call model. The return value of a device-interface function becomes the value returned by IOResult. If the return value is zero, the operation was successful.

To associate the device-interface functions with a specific file, you must write a customized Assign procedure. The Assign procedure must assign the addresses of the four device-interface functions to the four function pointers in the text-file variable. In addition, it should store the fmClosed "magic" constant in the Mode field, store the size of the text-file buffer in BufSize, store a pointer to the text-file buffer in BufPtr, and clear the Name string.

Assuming, for example, that the four device-interface functions are called DevOpen, DevInOut, DevFlush, and DevClose, the Assign procedure might look like this:

procedure AssignDev(var F: Text);

begin

with TextRec(F) do begin

Mode := fmClosed;

BufSize := SizeOf(Buffer); BufPtr := @Buffer; OpenFunc := @DevOpen; InOutFunc := @DevInOut; FlushFunc := @DevFlush; CloseFunc := @DevClose; Name[0] := #0;

end; end;

The device-interface functions can use the UserData field in the file record to store private information. This field isn't modified by the Delphi file system at any time.

The Open function

The Open function is called by the Reset, Rewrite, and Append standard procedures to open a text file associated with a device. On entry, the Mode field contains fmInput, fmOutput, or fmInOut to indicate whether the Open function was called from Reset, Rewrite, or Append.

The Open function prepares the file for input or output, according to the Mode value. If Mode specified fmInOut (indicating that Open was called from Append), it must be changed to fmOutput before Open returns.

Open is always called before any of the other device-interface functions. For that reason, AssignDev only initializes the OpenFunc field, leaving initialization of the remaining vectors up to Open. Based on Mode, Open can then install pointers to either input- or output-oriented functions. This saves the InOut, Flush functions and the CloseFile from determining the current mode.

The InOut function

The InOut function is called by the Read, Readln, Write, Writeln, Eof, Eoln, SeekEof, SeekEoln, and CloseFile standard procedures and functions whenever input or output from the device is required.

When Mode is fmInput, the InOut function reads up to BufSize characters into BufPtr^, and returns the number of characters read in BufEnd. In addition, it stores zero in BufPos. If the InOut function returns zero in BufEnd as a result of an input request, Eof becomes True for the file.

When Mode is fmOutput, the InOut function writes BufPos characters from BufPtr^, and returns zero in BufPos.

The Flush function

The Flush function is called at the end of each Read, Readln, Write, and Writeln. It can optionally flush the text-file buffer.

If Mode is fmInput, the Flush function can store zero in BufPos and BufEnd to flush the remaining (unread) characters in the buffer. This feature is seldom used.

If Mode is fmOutput, the Flush function can write the contents of the buffer exactly like the InOut function, which ensures that text written to the device appears on the device immediately. If Flush does nothing, the text doesn't appear on the device until the buffer becomes full or the file is closed.

The Close function

The Close function is called by the CloseFile standard procedure to close a text file associated with a device. (The Reset, Rewrite, and Append procedures also call Close if the file they are opening is already open.) If Mode is fmOutput, then before calling

Close, Object Pascal's file system calls the InOut function to ensure that all characters have been written to the device.

C h a p t e r