5 Standard IO
5 Standard IO
Introduction
• The standard I/O library handles such details as buffer allocation and
performing I/O in optimal-sized chunks.
• The standard I/O library was written by Dennis Ritchie around 1975.
• This library is specified by the ISO C standard because it has been
implemented on many operating systems other than the UNIX System.
Streams and FILE Objects
• With the ASCII character set, a single character is represented by a single byte.
• With international character sets, a character can be represented by more than
one byte.
• Standard I/O file streams can be used with both single-byte and multibyte
(‘‘wide’’) character sets.
• A stream’s orientation determines whether the characters that are read and
written are single byte or multibyte.
• To reference the stream, we pass its FILE pointer as an argument to each
standard I/O function.
• Here, we refer to a pointer to a FILE object, the type FILE *, as a file pointer.
• The fwide function can be used to set a stream’s orientation.
• The fwide function performs different tasks, depending on the value of the
mode argument.
• If the mode argument is negative, fwide will try to make the specified stream
byte oriented.
• If the mode argument is positive, fwide will try to make the specified stream
wide oriented.
• If the mode argument is zero, fwide will not try to set the orientation, but
will still return a value identifying the stream’s orientation.
Standard Input, Standard Output, and Standard Error
• These functions must be called after the stream has been opened (obviously,
since each requires a valid file pointer as its first argument) but before any other
operation is performed on the stream.
• At any time, we can force a stream to be flushed.
• The fflush function causes any unwritten data for the stream to be
passed to the kernel.
• As a special case, if fp is NULL, fflush causes all output streams to be
flushed.
Opening a Stream
• The fopen, freopen, and fdopen functions open a standard I/O stream.
The differences in these three functions are as follows:
1. The fopen function opens a specified file.
2. The freopen function opens a specified file on a specified stream, closing the stream
first if it is already open. If the stream previously had an orientation, freopen clears it.
This function is typically used to open a specified file as one of the predefined streams:
standard input, standard output, or standard error.
3. The fdopen function takes an existing file descriptor, which we could obtain from the
open, dup, dup2, fcntl, pipe, socket, socketpair, or accept functions, and
associates a standard I/O stream with the descriptor. This function is often used with
descriptors that are returned by the functions that create pipes and network
communication channels. Because these special types of files cannot be opened with the
standard I/O fopen function, we have to call the device-specific function to obtain a file
descriptor, and then associate this descriptor with a standard I/O stream using fdopen.
When a file is opened for reading and writing (the plus sign in the
type), two restrictions apply.
• Output cannot be directly followed by input without an intervening
fflush, fseek, fsetpos, or rewind.
• Any buffered output data is flushed before the file is closed. Any input data that
may be buffered is discarded. If the standard I/O library had automatically
allocated a buffer for the stream, that buffer is released.
• When a process terminates normally, either by calling the exit function directly
or by returning from the main function, all standard I/O streams with unwritten
buffered data are flushed and all open standard I/O streams are closed.
Reading and Writing a Stream
• The three types of unformatted I/O:
1. Character-at-a-time I/O. We can read or write one character at a time, with
the standard I/O functions handling all the buffering, if the stream is
buffered.
2. Line-at-a-time I/O. If we want to read or write a line at a time – using
fgets and fputs.
3. Direct I/O. This type of I/O is supported by the fread and fwrite
functions. For each I/O operation, we read or write some number of
objects, where each object is of a specified size. These two functions are
often used for binary files where we read or write a structure with each
operation.
Input Functions
• Three functions allow us to read one character at a time.
The function getchar is defined to be equivalent to getc(stdin). The difference
between getc and fgetc is that getc can be implemented as a macro, whereas
fgetc cannot be implemented as a macro. This means three things:
1. The argument to getc should not be an expression with side effects, because
it could be evaluated more than once.
2. Since fgetc is guaranteed to be a function, we can take its address. This
allows us to pass the address of fgetc as an argument to another function.
3. Calls to fgetc probably take longer than calls to getc, as it usually takes
more time to call a function.
• Note that these functions return the same value whether an error occurs or the
end of file is reached.
• To distinguish between the two, we must call either ferror or feof.
In most implementations, two flags are maintained for each stream in the FILE
object:
• An error flag
• An end-of-file flag
Both flags are cleared by calling clearerr.
Output Functions
• Output functions are available that correspond to each of the input functions
• Both specify the address of the buffer to read the line into. The gets function
reads from standard input, whereas fgets reads from the specified stream.
• With fgets, we have to specify the size of the buffer, n. This function reads up
through and including the next newline, but no more than n − 1 characters, into
the buffer
• The buffer is terminated with a null byte.
• If the line, including the terminating newline, is longer than n − 1, only a partial
line is returned, but the buffer is always null terminated.
• Another call to fgets will read what follows on the line.
• The gets function should never be used. The problem is that it doesn’t allow
the caller to specify the buffer size.
• This allows the buffer to overflow if the line is longer than the buffer, writing
over whatever happens to follow the buffer in memory.
• Line-at-a-time output is provided by fputs and puts.
• The function fputs writes the null-terminated string to the specified stream. The
null byte at the end is not written.
• The puts function writes the null-terminated string to the standard output,
without writing the null byte. But puts then writes a newline character to the
standard output.
Binary I/O
• The following two functions are provided for binary I/O.
• For the read case, this number can be less than nobj if an error occurs or if the
end of file is encountered.
• In this situation, ferror or feof must be called.
• For the write case, if the return value is less than the requested nobj, an error
has occurred.
Positioning a Stream
There are three ways to position a standard I/O stream:
1. The two functions ftell and fseek. They have been around since Version 7,
but they assume that a file’s position can be stored in a long integer.
2. The two functions ftello and fseeko. They were introduced in the Single
UNIX Specification to allow for file offsets that might not fit in a long integer.
They replace the long integer with the off_t data type.
3. The two functions fgetpos and fsetpos. They were introduced by ISO C.
They use an abstract data type, fpos_t, that records a file’s position. This
datatype can be made as big as necessary to record a file’s position.
• For a binary file, a file’s position indicator is measured in bytes from the
beginning of the file.
• The value returned by ftell for a binary file is this byte position. To position a
binary file using fseek, we must specify a byte offset and indicate how that offset
is interpreted.
• The values for whence are the same as for the lseek function: SEEK_SET means
from the beginning of the file, SEEK_CUR means from the current file position,
and SEEK_END means from the end of file.
• For text files, the file’s current position may not be measurable as a simple byte
offset.
• Again, this is mainly under non-UNIX systems that might store text files in a
different format.
• To position a text file, whence has to be SEEK_SET, and only two values for
offset are allowed: 0—meaning rewind the file to its beginning—or a value that
was returned by ftell for that file.
• A stream can also be set to the beginning of the file with the rewind function.
• The ftello function is the same as ftell, and the fseeko function is the
same as fseek, except that the type of the offset is off_t instead of long.
• The fgetpos function stores the current value of the file’s position indicator in
the object pointed to by pos.
• This value can be used in a later call to fsetpos to reposition the stream to
that location.