![]() |
![]() |
![]() |
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
![]() |
![]() |
[an error occurred while processing this directive]
Steps To use file stream classes in your programs:
How It Works These classes share the same base classes as the classes cin and cout, meaning they have the same functionality with a bit extra added. Because of this, your overloaded insertion and extraction operators should work fine with file streams as well. Just make sure that your overloaded operators work with istream and ostream objects. 15.2 Continually read data until the end of file?Problem The program seems to read from the file one more time than it is supposed to. Things such as counters are off by one, and the last item is processed twice. Technique This is a common problem for programmers. This particular off-by-one error is usually caused by the way the stream is read. Problem 1: The Reading Loop and Stream Errors All IOStreams overloaded operators return a reference to the stream that can be checked for validity after the attempt to read from the stream. The problem is that most programmers dont realize that reading to the end of the stream is not an error condition. However, attempting to read past the end of the stream will cause the stream to go to an end of file condition. This is important to remember in processing loops dealing with streams, and it might be necessary to add other conditions to ensure that the loop does not iterate once more than it should. For instance, the code while ( !inputfile.eof() ) { inputfile >> myString ; wordcount++ ; } will definitely cause the loop to execute once more than it should. Even if the last word is read from the file, the eof() member function will not return true because there is no error condition. The eof() function will return true on the next iteration because the extraction operator tried to read past the end of the file. Problem 2: Differing Implementation of the STL and Other Methods of Extracting Data Because the C++ 3 Standard is so new, it is possible to run into implementations of the STL that are not 100 percent compliant with the standard. For instance, when extracting to a string object, these implementations might use different methods of reading from the stream, and possibly reset error conditions. The sample code provided for this How-To provides two programs that accomplish the same thing: both open a file as a stream, read each line, count the words, lines, and characters, and print statistics at the end of it all including average word lengths. One implementation (fileread.cpp) uses STL strings, and the other (filerea2.cpp) uses a plain character array and the library function strlen() to determine the length. The second example runs identically on all platforms tested, but the first behaves quite differently. The following code is the read processing loop from fileread.cpp: while( infile.getline( temp, 128 ) ) { strstream buffer ; int pwords = words ; lines ++ ; buffer << temp << << ends ; while( buffer >> tmpstring && tmpstring.length() ) { words ++ ; totallen += tmpstring.length() ; tmpstring = ; } cout << words - pwords << : << temp << endl ; } The outer while loop reads from the input file, line by line. After that, the infile object is checked for validity. Because the program counts lines, it was not feasible to pull words directly from the file stream. Immediately inside the loop, an in-memory stream is declared into which the line is fed. strstreams work the same as all other streams, but work on memory areas. The ends stream modifier adds the terminating NULL byte to denote the end of the stream. The interesting thing here is that Borland C++s STL string class will generate correct output if the line is terminated with a space before the ends modifier, while this throws the STL included with GNU and EGCS compilers off. The code compiles and executes fine, but code compiled by the Borland and GNU compilers does not match. The inner while loop pulls all the individual words out of the in-memory stream, and then sizes and counts them. The additional check for string length and the assignment of an empty string to tmpstring are actually unnecessary, but are left there to make absolutely sure the code is not processing an empty string. The following code shows the processing loop from filerea2.cpp: while( infile.getline( temp, 128 ) ) { strstream buffer ; int pwords = words ; lines ++ ; buffer << temp << ends ; while( buffer >> tmpstring && strlen( tmpstring )) { words ++ ; totallen += strlen( tmpstring ) ; } cout << words - pwords << : << temp << endl ; } The preceding code does the same thing as the read processing loop from fileread.cpp, except it uses an array of char and string functions instead of the string class. The preceding code produces correct code with all compilers I have tested it with. The lesson here is that if time permits, experiment (that is, replace character strings with string class objects) when getting results that dont look right from code. Personally, I am surprised at the different output. If you want to compare the output from different compilers, I left the batch file used to compile, link, and execute the two programs using Borland C++ and DJGPP in the same directory as the source file. I used the source files as input for the program, with the output redirected to a file for easy comparison.
|
![]() |
Products | Contact Us | About Us | Privacy | Ad Info | Home
Use of this site is subject to certain Terms & Conditions, Copyright © 1996-1999 EarthWeb Inc. All rights reserved. Reproduction whole or in part in any form or medium without express written permision of EarthWeb is prohibited.
|