File System Basics. McGraw-Hill The Complete Reference Fourth Edition
Reklaam
Reklaam
214
C + + : T h e C o m p l e t e R e f e r e n c e a consistent interface. You need only think in terms of streams and use only one file system to accomplish all I/O operations. The I/O system automatically converts the raw input or output from each device into an easily managed stream.
File System Basics
The C file system is composed of several interrelated functions. The most common of these are shown in Table 9-1. They require the header stdio.h. C++ programs may also use the C++-style header <cstdio>.
Name fopen( ) fclose( ) putc( ) fputc( ) getc( ) fgetc( ) fgets( ) fputs( ) fseek( ) ftell( ) fprintf( ) fscanf( ) feof( ) ferror( ) rewind( ) remove( ) fflush( )
Function
Opens a file.
Closes a file.
Writes a character to a file.
Same as putc( ).
Reads a character from a file.
Same as getc( ).
Reads a string from a file.
Writes a string to a file.
Seeks to a specified byte in a file.
Returns the current file position.
Is to a file what printf( ) is to the console.
Is to a file what scanf( ) is to the console.
Returns true if end-of-file is reached.
Returns true if an error has occurred.
Resets the file position indicator to the beginning of the file.
Erases a file.
Flushes a file.
Table 9-1.
Commonly Used C File-System Functions
C h a p t e r 9 : F i l e I / O
215
The header file stdio.h and <cstdio> header provide the prototypes for the I/O functions and define these three types: size_t, fpos_t, and FILE. The size_t type is some variety of unsigned integer, as is fpos_t. The FILE type is discussed in the next section.
Also defined in stdio.h and <cstdio> are several macros. The ones relevant to this chapter are NULL, EOF, FOPEN_MAX, SEEK_SET, SEEK_CUR, and SEEK_END.
The NULL macro defines a null pointer. The EOF macro is generally defined as
−1 and is the value returned when an input function tries to read past the end of the file.
FOPEN_MAX
defines an integer value that determines the number of files that may be open at any one time. The other macros are used with fseek( ), which is the function that performs random access on a file.
The File Pointer
The file pointer is the common thread that unites the C I/O system. A file pointer is a pointer to a structure of type FILE. It points to information that defines various things about the file, including its name, status, and the current position of the file. In essence, the file pointer identifies a specific file and is used by the associated stream to direct the operation of the I/O functions. In order to read or write files, your program needs to use file pointers. To obtain a file pointer variable, use a statement like this:
FILE *fp;
Opening a File
The fopen( ) function opens a stream for use and links a file with that stream. Then it returns the file pointer associated with that file. Most often (and for the rest of this discussion), the file is a disk file. The fopen( ) function has this prototype:
FILE *fopen(const char *filename, const char *mode); where filename is a pointer to a string of characters that make up a valid filename and may include a path specification. The string pointed to by mode determines how the file will be opened. Table 9-2 shows the legal values for mode. Strings like "r+b" may also be represented as "rb+."
Mode r w a
Meaning
Open a text file for reading.
Create a text file for writing.
Append to a text file.
Table 9-2.
The Legal Values for Mode
216
C + + : T h e C o m p l e t e R e f e r e n c e
As stated, the fopen( ) function returns a file pointer. Your program should never alter the value of this pointer. If an error occurs when it is trying to open the file, fopen( ) returns a null pointer.
The following code uses fopen( ) to open a file named TEST for output.
FILE *fp; fp = fopen("test", "w");
While technically correct, you will usually see the preceding code written like this:
FILE *fp; if ((fp = fopen("test","w"))==NULL) { printf("Cannot open file.\n"); exit(1);
}
This method will detect any error in opening a file, such as a write-protected or a full disk, before your program attempts to write to it. In general, you will always want to confirm that fopen( ) succeeded before attempting any other operations on the file.
C h a p t e r 9 : F i l e I / O
217
Although most of the file modes are self-explanatory, a few comments are in order.
If, when opening a file for read-only operations, the file does not exist, fopen( ) will fail.
When opening a file using append mode, if the file does not exist, it will be created.
Further, when a file is opened for append, all new data written to the file will be written to the end of the file. The original contents will remain unchanged. If, when a file is opened for writing, the file does not exist, it will be created. If it does exist, the contents of the original file will be destroyed and a new file created. The difference between modes r+ and w+ is that r+ will not create a file if it does not exist; however, w+ will.
Further, if the file already exists, opening it with w+ destroys its contents; opening it with r+ does not.
As Table 9-2 shows, a file may be opened in either text or binary mode. In most implementations, in text mode, carriage return/linefeed sequences are translated to newline characters on input. On output, the reverse occurs: newlines are translated to carriage return/linefeeds. No such translations occur on binary files.
The number of files that may be open at any one time is specified by FOPEN_MAX.
This value will usually be at least 8, but you must check your compiler’s documentation for its exact value.
Closing a File
The fclose( ) function closes a stream that was opened by a call to fopen( ). It writes any data still remaining in the disk buffer to the file and does a formal operatingsystem-level close on the file. Failure to close a stream invites all kinds of trouble, including lost data, destroyed files, and possible intermittent errors in your program.
fclose( )
also frees the file control block associated with the stream, making it available for reuse. There is an operating-system limit to the number of open files you may have at any one time, so you may have to close one file before opening another.
The fclose( ) function has this prototype: int fclose(FILE *fp); where fp is the file pointer returned by the call to fopen( ). A return value of zero signifies a successful close operation. The function returns EOF if an error occurs. You can use the standard function ferror( ) (discussed shortly) to determine and report any problems.
Generally, fclose( ) will fail only when a disk has been prematurely removed from the drive or there is no more space on the disk.
Writing a Character
The C I/O system defines two equivalent functions that output a character: putc( ) and
fputc( )
. (Actually, putc( ) is usually implemented as a macro.) There are two identical functions simply to preserve compatibility with older versions of C. This book uses
putc( )
, but you can use fputc( ) if you like.
218
C + + : T h e C o m p l e t e R e f e r e n c e
The putc( ) function writes characters to a file that was previously opened for writing using the fopen( ) function. The prototype of this function is int putc(int ch, FILE *fp); where fp is the file pointer returned by fopen( ) and ch is the character to be output.
The file pointer tells putc( ) which file to write to. Although ch is defined as an int, only the low-order byte is written.
If a putc( ) operation is successful, it returns the character written. Otherwise, it returns EOF.
Reading a Character
There are also two equivalent functions that input a character: getc( ) and fgetc( ).
Both are defined to preserve compatibility with older versions of C. This book uses
getc( )
(which is usually implemented as a macro), but you can use fgetc( ) if you like.
The getc( ) function reads characters from a file opened in read mode by fopen( ).
The prototype of getc( ) is int getc(FILE *fp); where fp is a file pointer of type FILE returned by fopen( ). getc( ) returns an integer, but the character is contained in the low-order byte. Unless an error occurs, the highorder byte is zero.
The getc( ) function returns an EOF when the end of the file has been reached.
Therefore, to read to the end of a text file, you could use the following code: do { ch = getc(fp);
} while(ch!=EOF);
However, getc( ) also returns EOF if an error occurs. You can use ferror( ) to determine precisely what has occurred.
Using fopen( ), getc( ), putc( ), and fclose( )
The functions fopen( ), getc( ), putc( ), and fclose( ) constitute the minimal set of file routines. The following program, KTOD, is a simple example of using putc( ), fopen( ), and fclose( ). It reads characters from the keyboard and writes them to a disk file until the user types a dollar sign. The filename is specified from the command line. For example, if you call this program KTOD, typing KTOD TEST allows you to enter lines of text into the file called TEST.
C h a p t e r 9 : F i l e I / O
219
/* KTOD: A key to disk program. */
#include <stdio.h>
#include <stdlib.h> int main(int argc, char *argv[])
{
FILE *fp; char ch; if(argc!=2) { printf("You forgot to enter the filename.\n"); exit(1);
} if((fp=fopen(argv[1], "w"))==NULL) { printf("Cannot open file.\n"); exit(1);
} do { ch = getchar(); putc(ch, fp);
} while (ch != '$'); fclose(fp);
} return 0;
The complementary program DTOS reads any text file and displays the contents on the screen. It demonstrates getc( ).
/* DTOS: A program that reads files and displays them on the screen. */
#include <stdio.h>
#include <stdlib.h> int main(int argc, char *argv[])
{
FILE *fp; char ch;
220
C + + : T h e C o m p l e t e R e f e r e n c e if(argc!=2) { printf("You forgot to enter the filename.\n"); exit(1);
} if((fp=fopen(argv[1], "r"))==NULL) { printf("Cannot open file.\n"); exit(1);
} ch = getc(fp); /* read one character */ while (ch!=EOF) { putchar(ch); /* print on screen */ ch = getc(fp);
} fclose(fp);
} return 0;
To try these two programs, first use KTOD to create a text file. Then read its contents using DTOS.
Using feof( )
As just described, getc( ) returns EOF when the end of the file has been encountered.
However, testing the value returned by getc( ) may not be the best way to determine when you have arrived at the end of a file. First, the file system can operate on both text and binary files. When a file is opened for binary input, an integer value that will test equal to EOF may be read. This would cause the input routine to indicate an end-of-file condition even though the physical end of the file had not been reached. Second, getc( ) returns EOF when it fails and when it reaches the end of the file. Using only the return value of getc( ), it is impossible to know which occurred. To solve these problems, the
C file system includes the function feof( ), which determines when the end of the file has been encountered. The feof( ) function has this prototype: int feof(FILE *fp);
feof( )
returns true if the end of the file has been reached; otherwise, it returns 0. Therefore, the following routine reads a binary file until the end of the file is encountered:
C h a p t e r 9 : F i l e I / O
221 while(!feof(fp)) ch = getc(fp);
Of course, you can apply this method to text files as well as binary files.
The following program, which copies text or binary files, contains an example of
feof( )
. The files are opened in binary mode and feof( ) checks for the end of the file.
/* Copy a file. */
#include <stdio.h>
#include <stdlib.h> int main(int argc, char *argv[])
{
FILE *in, *out; char ch; if(argc!=3) { printf("You forgot to enter a filename.\n"); exit(1);
} if((in=fopen(argv[1], "rb"))==NULL) { printf("Cannot open source file.\n"); exit(1);
} if((out=fopen(argv[2], "wb")) == NULL) { printf("Cannot open destination file.\n"); exit(1);
}
/* This code actually copies the file. */ while(!feof(in)) { ch = getc(in); if(!feof(in)) putc(ch, out);
} fclose(in); fclose(out);
} return 0;
222
C + + : T h e C o m p l e t e R e f e r e n c e
Working with Strings: fputs( ) and fgets( )
In addition to getc( ) and putc( ), the C file system supports the related functions
fgets( )
and fputs( ), which read and write character strings from and to a disk file.
These functions work just like putc( ) and getc( ), but instead of reading or writing a single character, they read or write strings. They have the following prototypes: int fputs(const char *str, FILE *fp); char *fgets(char *str, int length, FILE *fp);
The fputs( ) function writes the string pointed to by str to the specified stream.
It returns EOF if an error occurs.
The fgets( ) function reads a string from the specified stream until either a newline character is read or length
−1 characters have been read. If a newline is read, it will be part of the string (unlike the gets( ) function). The resultant string will be null terminated. The function returns str if successful and a null pointer if an error occurs.
The following program demonstrates fputs( ). It reads strings from the keyboard and writes them to the file called TEST. To terminate the program, enter a blank line.
Since gets( ) does not store the newline character, one is added before each string is written to the file so that the file can be read more easily.
#include <stdio.h>
#include <stdlib.h>
#include <string.h> int main(void)
{ char str[80];
FILE *fp; if((fp = fopen("TEST", "w"))==NULL) { printf("Cannot open file.\n"); exit(1);
} do { printf("Enter a string (CR to quit):\n"); gets(str); strcat(str, "\n"); /* add a newline */ fputs(str, fp);
} while(*str!='\n');
} return 0;
C h a p t e r 9 : F i l e I / O
223
rewind( )
The rewind( ) function resets the file position indicator to the beginning of the file specified as its argument. That is, it "rewinds" the file. Its prototype is void rewind(FILE *fp); where fp is a valid file pointer.
To see an example of rewind( ), you can modify the program from the previous section so that it displays the contents of the file just created. To accomplish this, the program rewinds the file after input is complete and then uses fgets( ) to read back the file. Notice that the file must now be opened in read/write mode using "w+" for the mode parameter.
#include <stdio.h>
#include <stdlib.h>
#include <string.h> int main(void)
{ char str[80];
FILE *fp; if((fp = fopen("TEST", "w+"))==NULL) { printf("Cannot open file.\n"); exit(1);
} do { printf("Enter a string (CR to quit):\n"); gets(str); strcat(str, "\n"); /* add a newline */ fputs(str, fp);
} while(*str!='\n');
/* now, read and display the file */ rewind(fp); /* reset file position indicator to start of the file. */ while(!feof(fp)) { fgets(str, 79, fp); printf(str);
}
224
C + + : T h e C o m p l e t e R e f e r e n c e
} return 0;
ferror( )
The ferror( ) function determines whether a file operation has produced an error. The
ferror( )
function has this prototype: int ferror(FILE *fp); where fp is a valid file pointer. It returns true if an error has occurred during the last file operation; otherwise, it returns false. Because each file operation sets the error condition, ferror( ) should be called immediately after each file operation; otherwise, an error may be lost.
The following program illustrates ferror( ) by removing tabs from a file and substituting the appropriate number of spaces. The tab size is defined by TAB_SIZE.
Notice how ferror( ) is called after each file operation. To use the program, specify the names of the input and output files on the command line.
/* The program substitutes spaces for tabs in a text file and supplies error checking. */
#include <stdio.h>
#include <stdlib.h>
#define TAB_SIZE 8
#define IN 0
#define OUT 1 void err(int e); int main(int argc, char *argv[])
{
FILE *in, *out; int tab, i; char ch; if(argc!=3) { printf("usage: detab <in> <out>\n"); exit(1);
} if((in = fopen(argv[1], "rb"))==NULL) {
C h a p t e r 9 : F i l e I / O
225
} printf("Cannot open %s.\n", argv[1]); exit(1); if((out = fopen(argv[2], "wb"))==NULL) { printf("Cannot open %s.\n", argv[1]); exit(1);
} tab = 0; do { ch = getc(in); if(ferror(in)) err(IN);
/* if tab found, output appropriate number of spaces */ if(ch=='\t') { for(i=tab; i<8; i++) { putc(' ', out); if(ferror(out)) err(OUT);
} tab = 0;
} else { putc(ch, out); if(ferror(out)) err(OUT); tab++; if(tab==TAB_SIZE) tab = 0; if(ch=='\n' || ch=='\r') tab = 0;
}
} while(!feof(in)); fclose(in); fclose(out);
} return 0; void err(int e)
{ if(e==IN) printf("Error on input.\n"); else printf("Error on output.\n"); exit(1);
}
226
C + + : T h e C o m p l e t e R e f e r e n c e
Erasing Files
The remove( ) function erases the specified file. Its prototype is int remove(const char *filename);
It returns zero if successful; otherwise, it returns a nonzero value.
The following program erases the file specified on the command line. However, it first gives you a chance to change your mind. A utility like this might be useful to new computer users.
/* Double check before erasing. */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h> int main(int argc, char *argv[])
{ char str[80]; if(argc!=2) { printf("usage: xerase <filename>\n"); exit(1);
} printf("Erase %s? (Y/N): ", argv[1]); gets(str);
} if(toupper(*str)=='Y') if(remove(argv[1])) { printf("Cannot erase file.\n"); exit(1);
} return 0;
Flushing a Stream
If you wish to flush the contents of an output stream, use the fflush( ) function, whose prototype is shown here: int fflush(FILE *fp);
Laadi alla
Reklaam