




Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
An in-depth exploration of c++ file i/o, covering various ways to perform file operations, opening and closing files, reading and writing data, and handling end-of-file conditions. It also discusses the differences between text and binary files, as well as positioning and seeking in files.
Typology: Study notes
1 / 8
This page cannot be seen from the preview
Don't miss anything!





In a C++ program, there are several ways to do file IOâUnix, C standard IO, and C++ streams. Itâs somewhat confusing to see a mixture of similar approaches, so weâre going to focus on C++. This paper contains a description of the basics of C++ file IO. Revision 1 clarifies some language in various places and significantly changed the End-Of-File sectionâreplacing an obsolete means of detecting the end-of-file condition. Revision 2 removes the use of character arrays for strings, addresses file open flag combinations, explains the tellg/tellp functions, explains why file position isnât the same as character index, and points out a possible platform-dependent required argument for the ios::pos_type constructor.
The primary reference for this paper is âThe C++ Standard Library: A Tutorial and Referenceâ by Nicolai M Josuttis (Addison-Wesley, 1999, ISBN 0- 201 - 37926 - 0). C++ streams are mentioned in the texts for CPSC-121 and CPSC-131, but the treatment is brief and incomplete.
Part of the C++ Standard Library is the IOStream Library, and one of the classes defined by the latter is the file stream or fstream. To use this class, your program must include its header file: #include
Files are created or opened by the open function, which has two forms: file.open(name); file.open(name, flags);
The name argument is a traditional C string (char*); if name is declared as a C++ string, you should use the file streamâs c_str() conversion function: string name; . . . file.open(name.c_str()); The flags argument may be any meaningful combination of the following six flags: Flag Meaning ios::in Open for reading (default for istream) ios::out Open for writing (default for ostream) ios:app Always appends at the end when writing ios::ate Positions at the end of the file after opening (ate is short for âat endâ) ios::trunc Truncates file (removes its former contents) ios::binary Does no replacement of special characters during reading or writing, as is done for text files. These flags can be used in certain combinations, as defined in the following table. The ate or binary flags arenât shown, since they donât interact with any other flag; ate is the same as a seek to the end of the file and binary disables checking for special characters or character pairs. Flags Meaning in Reads (file must exist) out Empties and writes (creates file if it doesnât exist) out | trunc Empties and writes (creates file if it doesnât exist) out | app Appends (creates file if it doesnât exist) in | out Reads and writes; initial position is the beginning (file must exist) in | out | trunc Empties, reads, and writes (creates file if it doesnât exist) Combinations not shown in this table, except for those that merely add the ate or binary flags, are not legal.
The data in text files is limited to lines of ASCII characters; binary files contain bit patterns that have no such constraint. The most significant issue is that when test files are read, the file system interprets and may replace certain characters. In some file systems, the end of a line is represented by two characters, carriage return and line feed. When a file is accessed in text mode, the newline
To read a line of ASCII text, up to some maximum number of characters or a specified delimiter, you may say: char s[10]; file.getline(char*, sizeof(s), â:â); The terminating delimiter is read but not stored in the character array. The next read operation will begin at the character after that delimiter. For either of these forms of the getline function, the size argument must include the null at the end of a traditional C string. There are two possible ways a getline may finish:
Itâs quite common for programs to loop through a file, repeatedly calling the get , getline , or read functions until there is no more data to read. Early non-ANSI/ISO C++ compilers provided the boolean function file.eof() , which indicated whether the last input operation failed because it attempted to read past the end of the file. The implementations where sometimes inconsistent and confusing. The eof() condition might be true after the last bytes of the file had been read, because the read operation was looking for some terminating character and encountered the end of the file instead. Modern ANSI/ISO C++ IOstream libraries donât set the flag that the eof() function returns, making the function useless. The fail() function is the proper means for detecting the end-of-file condition. It returns true if an input operation doesnât succeed for any reason, which is usually either an illegal character, such as a letter when a digit is expected, or an end-of-file. It doesnât
have the eof() functionâs confusing behavior of returning true when the end-of-file is reached after successfully reading the remaining characters of a string. Hereâs an example of the programming pattern for data types other than string : while (1) { file.getline(s, sizeof(s)); if (file.fail() { break; } } The string example is only slightly different: while (1) { getline(file, s); if (file.fail() { break; } } In both examples, the check of fail() comes after the input operation; the only difference is the name of the input function itself.
When getline is used to read strings from files that contain an empty lineâthose with nothing except a newline at their endâit passes back a string whose size is zero, which seems quite logical. When the >> operator is used, the behavior seems slightly differentâit skips completely over those lines. If the remainder of the file consists only of empty lines, fail() will be true. To understand this behavior, remember that getline is used to read entire lines, including any leading or trailing whitespace in the line. The >> operator is used to read words, not lines; it skips whitespace before words and stops at whitespace after words. The newline character at the end of any line is just more whitespace to skip over while looking for the next word. If nothing but empty lines remain in the file, the >> operator will fail to find a word.
There are fewer options for writing to files. To write a single character, you may say: char c; file.put(c) To write a series of bytes that donât represent a line of ASCII text, you should say: char x[10]; . . file.write(x, sizeof(x));
A B C \r \l D The D characterâs index is still 4, but its file position is 5. There are two functions for finding the values of the current positions: absolutePosition = file.tellg(); absolutePosition = file.tellp(); They can be called before a read or write to determine the file position of the item being read or written.
Thereâs only one simple function to close a file when youâre finished with it: file.close();
There are several boolean functions that indicate whether an error has occurred and what the state of the file stream is. These functions return the setting of several of the fileâs internal state flags. Function Meaning file.good(); File stream is good; no unusual condition or error has occurred file.eof(); An end-of-file condition has been encountered. Warning: modern ANSI/ISO C++ IOstream libraries donât set the flag that this function returns. file.fail(); An error has occurred; includes fatal errors covered by bad(); file.bad(); A fatal error has occurred. In general, a fatal error is one that canât be corrected by retrying the operation. For example, a disk error during a read or write. A non-fatal error is one that may be correctable by retrying the operation, usually with some argument changed. For example, if you want to create a file only if it doesnât already exist, you might first try to open it in ios::in mode to see if it does. A true from file.fail() is the desired result; it tells you thereâs no file that youâd be overwriting. You would then open the file in ios::out mode, after a file.clear() to clear the error flag. A word of caution: when the internal flags are set, they remain set until they are explicitly cleared. Closing the file doesnât clear the flags, only this function does: file.clear(); Thereâs a common error thatâs made when using one fstream to handle multiple files, one at a time. A typical sequence of operations might be: