19.Chapter22 Input and Output-精简简版
19.Chapter22 Input and Output-精简简版
Chapter 22 Input/Output
Outlines
• 22.1 Streams
• 22.2 File Operations
• 22.3 Formatted I/O
• 22.4 Character I/O
• 22.5 Line I/O
• 22.6 Block I/O
• 22.7 File Positioning
2
Introduction
• C’s input/output library is the biggest and most
important part of the standard library.
• The <stdio.h> header is the primary
repository of input/output functions, including
printf, scanf, putchar, getchar, puts,
and gets.
• This chapter provides more information about
these six functions.
• It also introduces many new functions, most of
which deal with files.
3
22.1 Streams
• In C, the term stream means any source of input
or any destination for output.
• Many small programs obtain all their input from
one stream (the keyboard) and write all their
output to another stream (the screen).
• Larger programs may need additional streams.
• Streams often represent files stored on various
media.
• However, they could just as easily be associated
with devices such as network ports and printers.
4
22.1 Streams
• Standard Streams and Redirection
– <stdio.h> provides three standard streams:
5
22.1 Streams
• Standard Streams and Redirection
– Many operating systems allow these default
meanings to be changed via a mechanism known
as redirection.
6
22.1 Streams
• File Pointers
– Accessing a stream is done through a file pointer,
which has type FILE *.
– The FILE type is declared in <stdio.h>.
– Certain streams are represented by file pointers with
standard names.
– Additional file pointers can be declared as needed:
FILE *fp1, *fp2;
7
22.1 Streams
• Text Files versus Binary Files
– <stdio.h> supports two kinds of files: text and
binary.
– The bytes in a text file represent characters, allowing
humans to examine or edit the file.
• The source code for a C program is stored in a text file.
– In a binary file, bytes don’t necessarily represent
characters.
• Groups of bytes might represent other types of data,
such as integers and floating-point numbers.
• An executable C program is stored in a binary file.
8
22.1 Streams
• Text Files versus Binary Files
– When data is written to a file, it can be stored in text
form or in binary form.
– One way to store the number 32767 in a file would
be to write it in text form as the characters 3, 2, 7, 6,
and 7:
9
22.1 Streams
• Text Files versus Binary Files
– The other option is to store the number in binary,
which would take as few as two bytes:
10
22.1 Streams
• Text Files versus Binary Files
– Text files have two characteristics that binary files
don’t possess.
– Text files are divided into lines. Each line in a text file
normally ends with one or two special characters.
• Windows: carriage-return character ('\x0d')
followed by line-feed character ('\x0a')
• UNIX and newer versions of Mac OS: line-feed
character
• Older versions of Mac OS: carriage-return character
11
22.1 Streams
• Text Files versus Binary Files
– Text files may contain a special “end-of-file”
marker.
• In Windows, the marker is '\x1a' (Ctrl-Z), but it
is not required.
• Most other operating systems, including UNIX,
have no special end-of-file character.
– In a binary file, there are no end-of-line or end-of-
file markers; all bytes are treated equally.
12
22.1 Streams
• Text Files versus Binary Files
– Programs that read from a file or write to a file must
take into account whether it’s text or binary.
– A program that displays the contents of a file on the
screen will probably assume it’s a text file.
– A file-copying program, on the other hand, can’t
assume that the file to be copied is a text file.
• If it does, binary files containing an end-of-file
character won’t be copied completely.
– When we can’t say for sure whether a file is text or
binary, it’s safer to assume that it’s binary.
13
22.2 File Operations
• Simplicity is one of the attractions of input and
output redirection.
• Unfortunately, redirection is too limited for many
applications.
– When a program relies on redirection, it has no control
over its files; it doesn’t even know their names.
– Redirection doesn’t help if the program needs to read
from two files or write to two files at the same time.
• When redirection isn’t enough, we’ll use the file
operations that <stdio.h> provides.
14
22.2 File Operations
• Opening a File
– Opening a file for use as a stream requires a call of the
fopen function.
– Prototype for fopen:
FILE *fopen(const char * filename,
const char * mode);
– filename is the name of the file to be opened.
• This argument may include information about the file’s
location, such as a drive specifier or path.
– mode is a “mode string” that specifies what operations
we intend to perform on the file.
15
22.2 File Operations
• Opening a File
– In Windows, be careful when the file name in a call of
fopen includes the \ character.
– The call fopen("c:\project\test1.dat", "r")
will fail, because \t is treated as a character escape.
– One way to avoid the problem is to use \\ instead
of \:
fopen("c:\\project\\test1.dat", "r")
– An alternative is to use the / character instead of \:
fopen("c:/project/test1.dat", "r")
16
22.2 File Operations
• Opening a File
– fopen returns a file pointer that the program can
(and usually will) save in a variable:
fp = fopen("in.dat", "r");
/* opens in.dat for reading */
– When it can’t open a file, fopen returns a null
pointer.
17
22.2 File Operations
• Modes
– Factors that determine which mode string to pass
to fopen:
• Which operations are to be performed on the file
• Whether the file contains text or binary data
– Mode strings for text files:
String Meaning
"r" Open for reading
"w" Open for writing (file need not exist)
"a" Open for appending (file need not exist)
"r+" Open for reading and writing, starting at beginning
"w+" Open for reading and writing (truncate if file exists)
"a+" Open for reading and writing (append if file exists)
18
22.2 File Operations
• Modes
– Mode strings for binary files:
String Meaning
"rb" Open for reading
"wb" Open for writing (file need not exist)
"ab" Open for appending (file need not exist)
"r+b" or "rb+" Open for reading and writing, starting at
beginning
"w+b" or "wb+" Open for reading and writing (truncate if file
exists)
"a+b" or "ab+" Open for reading and writing (append if file
exists)
19
22.2 File Operations
• Modes
– Note that there are different mode strings for writing data
and appending data.
– When data is written to a file, it normally overwrites what
was previously there.
– When a file is opened for appending, data written to the file
is added at the end.
– Special rules apply when a file is opened for both reading
and writing.
• Can’t switch from reading to writing without first calling a
file-positioning function unless the reading operation
encountered the end of the file.
• Can’t switch from writing to reading without either calling
fflush or calling a file-positioning function.
20
22.2 File Operations
• Closing a File
– The fclose function allows a program to close a file
that it’s no longer using.
– The argument to fclose must be a file pointer
obtained from a call of fopen or freopen.
– fclose returns zero if the file was closed
successfully.
– Otherwise, it returns the error code EOF (a macro
defined in <stdio.h>).
21
22.2 File Operations
• Closing a File
– The outline of a program that opens a file for reading:
#include <stdio.h>
#include <stdlib.h>
#define FILE_NAME "example.dat"
int main(void)
{
FILE *fp;
fp = fopen(FILE_NAME, "r");
if (fp == NULL) {
printf("Can't open %s\n", FILE_NAME);
exit(EXIT_FAILURE);
}
…
fclose(fp);
return 0;
}
22
22.2 File Operations
• Closing a File
– It’s not unusual to see the call of fopen combined
with the declaration of fp:
FILE *fp = fopen(FILE_NAME, "r");
or the test against NULL:
if ((fp = fopen(FILE_NAME, "r")) == NULL)
…
23
22.2 File Operations
• Miscellaneous File Operations
– The remove and rename functions allow a program
to perform basic file management operations.
– Unlike most other functions in this section, remove
and rename work with file names instead of file
pointers.
– Both functions return zero if they succeed and a
nonzero value if they fail.
24
22.2 File Operations
• Miscellaneous File Operations
– remove deletes a file:
remove("foo");
/* deletes the file named "foo" */
– If a program uses fopen (instead of tmpfile)
to create a temporary file, it can use remove to
delete the file before the program terminates.
– The effect of removing a file that’s currently open
is implementation-defined.
25
22.2 File Operations
• Miscellaneous File Operations
– rename changes the name of a file:
rename("foo", "bar");
/* renames "foo" to "bar" */
– rename is handy for renaming a temporary file
created using fopen if a program should decide to
make it permanent.
• If a file with the new name already exists, the effect
is implementation-defined.
– rename may fail if asked to rename an open file.
26
22.3 Formatted I/O
• The next group of library functions use format strings
to control reading and writing.
• printf and related functions are able to convert
data from numeric form to character form during
output.
• scanf and related functions are able to convert
data from character form to numeric form during
input.
27
22.3 Formatted I/O
• The …printf Functions
– The fprintf and printf functions write a variable
number of data items to an output stream, using a format
string to control the appearance of the output.
– The prototypes for both functions end with the ... symbol
(an ellipsis), which indicates a variable number of additional
arguments:
int fprintf(FILE * restrict stream,
const char * restrict format, ...);
int printf(const char * restrict format, ...);
– Both functions return the number of characters written; a
negative return value indicates that an error occurred.
28
22.3 Formatted I/O
• The …printf Functions
– printf always writes to stdout, whereas fprintf
writes to the stream indicated by its first argument:
printf("Total: %d\n", total);
/* writes to stdout */
fprintf(fp, "Total: %d\n", total);
/* writes to fp */
– A call of printf is equivalent to a call of fprintf
with stdout as the first argument.
29
22.3 Formatted I/O
• The …printf Functions
– fprintf works with any output stream.
– One of its most common uses is to write error
messages to stderr:
fprintf(stderr, "Error: data file can't
be opened.\n");
– Writing a message to stderr guarantees that it will
appear on the screen even if the user redirects
stdout.
30
22.3 Formatted I/O
• The …scanf Functions
– fscanf and scanf read data items from an input
stream, using a format string to indicate the layout
of the input.
– After the format string, any number of pointers—
each pointing to an object—follow as additional
arguments.
– Input items are converted (according to conversion
specifications in the format string) and stored in
these objects.
31
22.3 Formatted I/O
• The …scanf Functions
– scanf always reads from stdin, whereas fscanf
reads from the stream indicated by its first argument:
scanf("%d%d", &i, &j);
/* reads from stdin */
fscanf(fp, "%d%d", &i, &j);
/* reads from fp */
– A call of scanf is equivalent to a call of fscanf with
stdin as the first argument.
32
22.3 Formatted I/O
• The …scanf Functions
– Errors that cause the …scanf functions to return
prematurely:
• Input failure (no more input characters could be read)
• Matching failure (the input characters didn’t match the
format string)
33
22.3 Formatted I/O
• The …scanf Functions
– The …scanf functions return the number of data
items that were read and assigned to objects.
– They return EOF if an input failure occurs before any
data items can be read.
– Loops that test scanf’s return value are common.
– A loop that reads a series of integers one by one,
stopping at the first sign of trouble:
while (scanf("%d", &i) == 1) {
…
}
34
22.3 Formatted I/O
• Detecting End-of-File and Error Conditions
– If we ask a …scanf function to read and store n data
items, we expect its return value to be n.
– If the return value is less than n, something went
wrong:
• End-of-file. The function encountered end-of-file before
matching the format string completely.
• Read error. The function was unable to read characters
from the stream.
• Matching failure. A data item was in the wrong format.
35
22.3 Formatted I/O
• Detecting End-of-File and Error Conditions
– Every stream has two indicators associated with it:
an error indicator and an end-of-file indicator.
– These indicators are cleared when the stream is
opened.
– Encountering end-of-file sets the end-of-file
indicator, and a read error sets the error indicator.
• The error indicator is also set when a write error
occurs on an output stream.
– A matching failure doesn’t change either indicator.
36
22.3 Formatted I/O
• Detecting End-of-File and Error Conditions
– Once the error or end-of-file indicator is set, it
remains in that state until it’s explicitly cleared,
perhaps by a call of the clearerr function.
– clearerr clears both the end-of-file and error
indicators:
clearerr(fp);
/*clears eof and error indicators for fp */
– clearerr isn’t needed often, since some of the
other library functions clear one or both indicators as
a side effect.
37
22.3 Formatted I/O
• Detecting End-of-File and Error Conditions
– The feof and ferror functions can be used to test
a stream’s indicators to determine why a prior
operation on the stream failed.
– The call feof(fp) returns a nonzero value if the
end-of-file indicator is set for the stream associated
with fp.
– The call ferror(fp) returns a nonzero value if the
error indicator is set.
38
22.3 Formatted I/O
• Detecting End-of-File and Error Conditions
– When scanf returns a smaller-than-expected value,
feof and ferror can be used to determine the
reason.
• If feof returns a nonzero value, the end of the input
file has been reached.
• If ferror returns a nonzero value, a read error
occurred during input.
• If neither returns a nonzero value, a matching failure
must have occurred.
– The return value of scanf indicates how many data
items were read before the problem occurred.
39
22.3 Formatted I/O
• Detecting End-of-File and Error Conditions
– The find_int function is an example that shows
how feof and ferror might be used.
– find_int searches a file for a line that begins with
an integer:
n = find_int("foo");
– find_int returns the value of the integer that it
finds or an error code:
–1 File can’t be opened
–2 Read error
–3 No line begins with an integer
40
int find_int(const char *filename)
{
FILE *fp = fopen(filename, "r");
int n;
if (fp == NULL)
return -1; /* can't open file */
while (fscanf(fp, "%d", &n) != 1) {
if (ferror(fp)) {
fclose(fp);
return -2; /* read error */
}
if (feof(fp)) {
fclose(fp);
return -3; /* integer not found */
}
fscanf(fp, "%*[^\n]"); /* skips rest of line */
}
fclose(fp);
return n;
}
41
22.4 Character I/O
• The next group of library functions can read and
write single characters.
• These functions work equally well with text streams
and binary streams.
• The functions treat characters as values of type int,
not char.
• One reason is that the input functions indicate an
end-of-file (or error) condition by returning EOF,
which is a negative integer constant.
42
22.4 Character I/O
• Output Functions
– putchar writes one character to the stdout
stream:
putchar(ch); /* writes ch to stdout */
– fputc writes a character to an arbitrary stream:
fputc(ch, fp); /* writes ch to fp */
43
22.4 Character I/O
• Input Functions
– getchar reads a character from stdin:
ch = getchar();
– fgetc reads a character from an arbitrary stream:
ch = fgetc(fp);
– All functions treat the character as an unsigned
char value (which is then converted to int type
before it’s returned).
– As a result, they never return a negative value other
than EOF.
44
22.4 Character I/O
• Input Functions
– The fgetc and getchar functions behave the same
if a problem occurs.
– At end-of-file, they set the stream’s end-of-file
indicator and return EOF.
– If a read error occurs, they set the stream’s error
indicator and return EOF.
– To differentiate between the two situations, we can
call either feof or ferror.
45
22.4 Character I/O
• Input Functions
– One of the most common uses of fgetc and
getchar is to read characters from a file.
– A typical while loop for that purpose:
while ((ch = fgetc(fp)) != EOF) {
…
}
– Always store the return value in an int variable, not
a char variable.
– Testing a char variable against EOF may give the
wrong result.
46
22.4 Character I/O
• Input Functions
– The ungetc function “pushes back” a character read
from a stream and clears the stream’s end-of-file
indicator.
– A loop that reads a series of digits, stopping at the
first nondigit:
while (isdigit(ch = fgetc(fp))) {
…
}
ungetc(ch, fp);
/* pushes back last character read */
47
22.4 Character I/O
• Input Functions
– The number of characters that can be pushed back by
consecutive calls of ungetc varies; only the first call
is guaranteed to succeed.
– Calling a file-positioning function (fseek, fsetpos,
or rewind) causes the pushed-back characters to be
lost.
– ungetc returns the character it was asked to push
back.
• It returns EOF if an attempt is made to push back EOF
or to push back more characters than allowed.
48
22.5 Line I/O
• Library functions in the next group are able to
read and write lines.
• These functions are used mostly with text
streams, although it’s legal to use them with
binary streams as well.
49
22.5 Line I/O
• Output Functions
– The puts function writes a string of characters to stdout:
puts("Hi, there!");/* writes to stdout*/
– After it writes the characters in the string, puts always adds
a new-line character.
– fputs is a more general version of puts.
– Its second argument indicates the stream to which the
output should be written:
fputs("Hi, there!", fp);/*writes to fp*/
– Unlike puts, the fputs function doesn’t write a new-line
character unless one is present in the string.
– Both functions return EOF if a write error occurs; otherwise,
they return a nonnegative number.
50
22.5 Line I/O
• Input Functions
– The gets function reads a line of input from stdin:
gets(str); /* reads a line from stdin
*/
– gets reads characters one by one, storing them in
the array pointed to by str, until it reads a new-line
character (which it discards).
– fgets is a more general version of gets that can
read from any stream.
– fgets is also safer than gets, since it limits the
number of characters that it will store.
51
22.5 Line I/O
• Input Functions
– Both gets and fgets return a null pointer if a read
error occurs or they reach the end of the input stream
before storing any characters.
– Otherwise, both return their first argument, which
points to the array in which the input was stored.
– Both functions store a null character at the end of the
string.
52
22.6 Block I/O
53
22.6 Block I/O
• fwrite is designed to copy an array from memory to a stream.
• Arguments in a call of fwrite:
– Address of array
– Size of each array element (in bytes)
– Number of elements to write
– File pointer
• A call of fwrite that writes the entire contents of the array a:
fwrite(a, sizeof(a[0]),
sizeof(a) / sizeof(a[0]), fp);
• fwrite returns the number of elements actually written.
• This number will be less than the third argument if a write error
occurs.
54
22.6 Block I/O
• fread will read the elements of an array from a
stream.
• A call of fread that reads the contents of a file into
the array a:
n = fread(a, sizeof(a[0]),
sizeof(a) / sizeof(a[0]), fp);
• fread’s return value indicates the actual number of
elements read.
• This number should equal the third argument unless
the end of the input file was reached or a read error
occurred.
55
22.6 Block I/O
• fwrite is convenient for a program that needs to
store data in a file before terminating.
• Later, the program (or another program) can use
fread to read the data back into memory.
• The data doesn’t need to be in array form.
• A call of fwrite that writes a structure variable s
to a file:
fwrite(&s, sizeof(s), 1, fp);
56
22.7 File Positioning
• Every stream has an associated file position.
• When a file is opened, the file position is set at the
beginning of the file.
– In “append” mode, the initial file position may be
at the beginning or end, depending on the
implementation.
• When a read or write operation is performed, the file
position advances automatically, providing sequential
access to data.
57
22.7 File Positioning
• Although sequential access is fine for many
applications, some programs need the ability to jump
around within a file.
• If a file contains a series of records, we might want to
jump directly to a particular record.
• <stdio.h> provides five functions that allow a
program to determine the current file position or to
change it.
58
22.7 File Positioning
• The fseek function changes the file position
associated with the first argument (a file pointer).
• The third argument is one of three macros:
SEEK_SET Beginning of file
SEEK_CUR Current file position
SEEK_END End of file
• The second argument, which has type long
int, is a (possibly negative) byte count.
59
22.7 File Positioning
• Using fseek to move to the beginning of a file:
fseek(fp, 0L, SEEK_SET);
• Using fseek to move to the end of a file:
fseek(fp, 0L, SEEK_END);
• Using fseek to move back 10 bytes:
fseek(fp, -10L, SEEK_CUR);
• If an error occurs (the requested position doesn’t
exist, for example), fseek returns a nonzero value.
60
22.7 File Positioning
• The file-positioning functions are best used with
binary streams.
• C doesn’t prohibit programs from using them with
text streams, but certain restrictions apply.
• For text streams, fseek can be used only to move
to the beginning or end of a text stream or to
return to a place that was visited previously.
• For binary streams, fseek isn’t required to
support calls in which the third argument is
SEEK_END.
61
22.7 File Positioning
• The ftell function returns the current file
position as a long integer.
• The value returned by ftell may be saved and
later supplied to a call of fseek:
long file_pos;
…
file_pos = ftell(fp);
/* saves current position */
…
fseek(fp, file_pos, SEEK_SET);
/* returns to old position */
62
22.7 File Positioning
• If fp is a binary stream, the call ftell(fp)
returns the current file position as a byte count,
where zero represents the beginning of the file.
• If fp is a text stream, ftell(fp) isn’t necessarily
a byte count.
• As a result, it’s best not to perform arithmetic on
values returned by ftell.
63
22.7 File Positioning
• The rewind function sets the file position at
the beginning.
• The call rewind(fp) is nearly equivalent to
fseek(fp, 0L, SEEK_SET).
– The difference? rewind doesn’t return a value
but does clear the error indicator for fp.
64
22.7 File Positioning
• fseek and ftell are limited to files whose
positions can be stored in a long integer.
• For working with very large files, C provides two
additional functions: fgetpos and fsetpos.
• These functions can handle large files because they
use values of type fpos_t to represent file
positions.
– An fpos_t value isn’t necessarily an integer; it
could be a structure, for instance.
65
22.7 File Positioning
• The call fgetpos(fp, &file_pos) stores the
file position associated with fp in the file_pos
variable.
• The call fsetpos(fp, &file_pos) sets the file
position for fp to be the value stored in file_pos.
• If a call of fgetpos or fsetpos fails, it stores an
error code in errno.
• Both functions return zero when they succeed and a
nonzero value when they fail.
66
22.7 File Positioning
• An example that uses fgetpos and fsetpos to
save a file position and return to it later:
fpos_t file_pos;
…
fgetpos(fp, &file_pos);
/* saves current position */
…
fsetpos(fp, &file_pos);
/* returns to old position */
67
22.7 File Positioning
• Program: Modifying a File of Part Records
– Actions performed by the invclear.c
program:
• Opens a binary file containing part structures.
• Reads the structures into an array.
• Sets the on_hand member of each structure to 0.
• Writes the structures back to the file.
– The program opens the file in "rb+" mode,
allowing both reading and writing.
68
invclear.c
/* Modifies a file of part records by setting the
quantity on hand to zero for all records */
#include <stdio.h>
#include <stdlib.h>
#define NAME_LEN 25
#define MAX_PARTS 100
struct part {
int number;
char name[NAME_LEN+1];
int on_hand;
} inventory[MAX_PARTS];
int num_parts;
69
int main(void)
{ FILE *fp;
int i;
rewind(fp);
fwrite(inventory, sizeof(struct part), num_parts,
fp);
fclose(fp);
return 0;
}
70
The End
71