Go to the first, previous, next, last section, table of contents.

# The old I/O library

WARNING: This chapter describes classes that are obsolete. These classes are normally not available when libg++ is installed normally. The sources are currently included in the distribution, and you can configure libg++ to use these classes instead of the new iostream classes. This is only a temporary measure; you should convert your code to use iostreams as soon as possible. The iostream classes provide some compatibility support, but it is very incomplete (there is no longer a `File` class).

## File-based classes

The `File` class supports basic IO on Unix files. Operations are based on common C stdio library functions.

`File` serves as the base class for istreams, ostreams, and other derived classes. It contains the interface between the Unix stdio file library and these more structured classes. Most operations are implemented as simple calls to stdio functions. `File` class operations are also fully compatible with raw system file reads and writes (like the system `read` and `lseek` calls) when buffering is disabled (see below). The `FILE*` stdio file pointer is, however maintained as protected. Classes derived from File may only use the IO operations provided by File, which encompass essentially all stdio capabilities.

The class contains four general kinds of functions: methods for binding `File`s to physical Unix files, basic IO methods, file and buffer control methods, and methods for maintaining logical and physical file status.

Binding and related tasks are accomplished via `File` constructors and destructors, and member functions `open, close, remove, filedesc, name, setname`.

If a file name is provided in a constructor or open, it is maintained as class variable `nm` and is accessible via `name`. If no name is provided, then `nm` remains null, except that `Files` bound to the default files stdin, stdout, and stderr are automatically given the names `(stdin), (stdout), (stderr)` respectively. The function `setname` may be used to change the internal name of the `File`. This does not change the name of the physical file bound to the File. The member function `close` closes a file. The `~File` destructor closes a file if it is open, except that stdin, stdout, and stderr are flushed but left open for the system to close on program exit since some systems may require this, and on others it does not matter. `remove` closes the file, and then deletes it if possible by calling the system function to delete the file with the name provided in the `nm` field.

## Basic IO

- `read` and `write` perform binary IO via stdio `fread` and `fwrite`.
- `get` and `put` for chars invoke stdio `getc` and `putc` macros.
- `put(const char* s)` outputs a null-terminated string via stdio `fputs`.
- `unget` and `putback` are synonyms. Both call stdio `ungetc`.

## File Control

`flush`, `seek`, `tell`, and `tell` call the corresponding stdio functions.

`flush(char)` and `fill()` call stdio `_flsbuf` and `_filbuf` respectively.

`setbuf` is mainly useful to turn off buffering in cases where nonsequential binary IO is being performed. `raw` is a synonym for `setbuf(_IONBF)`. After a `f.raw()`, using the stdio functions instead of the system `read, write`, etc., calls entails very little overhead. Moreover, these become fully compatible with intermixed system calls (e.g., `lseek(f.filedesc(), 0, 0)`). While intermixing `File` and system IO calls is not at all recommended, this technique does allow the `File` class to be used in conjunction with other functions and libraries already set up to operate on file descriptors. `setbuf` should be called at most once after a constructor or open, but before any IO.

## File Status

File status is maintained in several ways.

A `File` may be checked for accessibility via `is_open()`, which returns true if the File is bound to a usable physical file, `readable()`, which returns true if the File can be read from (opened for reading, and not in a _fail state), or `writable()`, which returns true if the File can be written to.

`File` operations return their status via two means: failure and success are represented via the logical state. Also, the return values of invoked stdio and system functions that return useful numeric values (not just failure/success flags) are held in a class variable accessible via `iocount`. (This is useful, for example, in determining the number of items actually read by the `read` function.)

Like the AT&T i/o-stream classes, but unlike the description in the Stroustrup book, p238, `rdstate()` returns the bitwise OR of `_eof`, `_fail` and `_bad`, not necessarily distinct values. The functions `eof()`, `fail()`, `bad()`, and `good()` can be used to test for each of these conditions independently.

`_fail` becomes set for any input operation that could not read in the desired data, and for other failed operations. As with all Unix IO, `_eof` becomes true only when an input operations fails because of an end of file. Therefore, `_eof` is not immediately true after the last successful read of a file, but only after one final read attempt. Thus, for input operations, `_fail` and `_eof` almost always become true at the same time. `bad` is set for unbound files, and may also be set by applications in order to communicate input corruption. Conversely, `_good` is defined as 0 and is returned by `rdstate()` if all is well.

The state may be modified via `clear(flag)`, which, despite its name, sets the corresponding state_value flag. `clear()` with no arguments resets the state to `_good`. `failif(int cond)` sets the state to `_fail` only if `cond` is true.

Errors occuring during constructors and file opens also invoke the function `error`. `error` in turn calls a resetable error handling function pointed to by the non-member global variable `File_error_handler` only if a system error has been generated. Since `error` cannot tell if the current system error is actually responsible for a failure, it may at times print out spurious messages. Three error handlers are provided. The default, `verbose_File_error_handler` calls the system function `perror` to print the corresponding error message on standard error, and then returns to the caller. `quiet_File_error_handler` does nothing, and simply returns. `fatal_File_error_handler` prints the error and then aborts execution. These three handlers, or any other user-defined error handlers can be selected via the non-member function `set_File_error_handler`.

All read and write operations communicate either logical or physical failure by setting the `_fail` flag. All further operations are blocked if the state is in a `_fail` or`_bad` condition. Programmers must explicitly use `clear()` to reset the state in order to continue IO processing after either a logical or physical failure. C programmers who are unfamiliar with these conventions should note that, unlike the stdio library, `File` functions indicate IO success, status, or failure solely through the state, not via return values of the functions. The `void*` operator or `rdstate()` may be used to test success. In particular, according to c++ conversion rules, the `void*` coercion is automatically applied whenever the `File&` return value of any `File` function is tested in an `if` or `while`. Thus, for example, an easy way to copy all of stdin to stdout until eof (at which point `get` fails) or some error is `char c; while(cin.get(c) && cout.put(c));`.

The current version of istreams and ostreams differs significantly from previous versions in order to obtain compatibility with AT&T 1.2 streams. Most code using previous versions should still work. However, the following features of `File` are not incorporated in streams (they are still present in `File`): `scan(const char* fmt...), remove(), read(), write(), setbuf(), raw()`. Additionally, the feature of previous streams that allowed free intermixing of stream and stdio input and output is no longer guaranteed to always behave as desired.

Go to the first, previous, next, last section, table of contents.