} ///:~
An ifstreamis created using the source code file for this program as an argument. The assure( )function reports a failure if the file cannot be opened. All the work really happens in the statement: .
cout << in.rdbuf();
which sends the entire contents of the file to cout. This is not only more succinct to code, it is often more efficient than moving the bytes one at a time .
A form of get( )allows you to write directly into the streambufof another object. The first argument is a reference to the destination streambuf,and the second is the terminating character (‘ \n’by default), which stops the get( )function. So there is yet another way to print a file to standard output: .
//: C04:Sbufget.cpp
// Copies a file to standard output
#include
#include
#include "../require.h"
using namespace std;
int main() {
ifstream in("Sbufget.cpp");
assure(in);
streambuf& sb = *cout.rdbuf();
while (!in.get(sb).eof()) {
if (in.fail()) // Found blank line
in.clear();
cout << char(in.get()); // Process '\n'
}
} ///:~
The rdbuf( )function returns a pointer, so it must be dereferenced to satisfy the function’s need to see an object. Stream buffers are not meant to be copied (they have no copy constructor), so we define sbas a reference to cout’s stream buffer. We need the calls to fail( )and clear( )in case the input file has a blank line (this one does). When this particular overloaded version of get( )sees two newlines in a row (evidence of a blank line), it sets the input stream’s fail bit, so we must call clear( )to reset it so that the stream can continue to be read. The second call to get( )extracts and echoes each newline delimiter. (Remember, the get( )function doesn’t extract its delimiter like getline( )does.) .
You probably won’t need to use a technique like this often, but it’s nice to know it exists. [43] A more in-depth treatment of stream buffers and streams in general can be found in Langer & Kreft’s, Standard C++ IOStreams and Locales , Addison-Wesley, 1999.
Each type of iostream has a concept of where its "next" character will come from (if it’s an istream) or go (if it’s an ostream). In some situations, you might want to move this stream position. You can do so using two models: one uses an absolute location in the stream called the streampos; the second works like the Standard C library functions fseek( )for a file and moves a given number of bytes from the beginning, end, or current position in the file .
The streamposapproach requires that you first call a "tell" function: tellp( )for an ostreamor tellg( )for an istream. (The "p" refers to the "put pointer," and the "g" refers to the "get pointer.") This function returns a streamposyou can later use in calls to seekp( )for an ostreamor seekg( )for an istream, when you want to return to that position in the stream .
The second approach is a relative seek and uses overloaded versions of seekp( )and seekg( ). The first argument is the number of characters to move: it can be positive or negative. The second argument is the seek direction: .
ios::beg |
From beginning of stream |
ios::cur |
Current position in stream |
ios::end |
From end of stream |
Here’s an example that shows the movement through a file, but remember, you’re not limited to seeking within files, as you are with C and cstdio. With C++, you can seek in any type of iostream (although the standard stream objects, such as cinand cout, explicitly disallow it): .
//: C04:Seeking.cpp
// Seeking in iostreams
#include
#include
#include
#include
#include "../require.h"
using namespace std;
int main() {
const int STR_NUM = 5, STR_LEN = 30;
char origData[STR_NUM][STR_LEN] = {
"Hickory dickory dus. . .",
"Are you tired of C++?",
"Well, if you have,",
"That's just too bad,",
"There's plenty more for us!"
};
char readData[STR_NUM][STR_LEN] = { 0 };
ofstream out("Poem.bin", ios::out | ios::binary);
assure(out, "Poem.bin");
for(size_t i = 0; i < STR_NUM; i++)
out.write(origData[i], STR_LEN);
out.close();
ifstream in("Poem.bin", ios::in | ios::binary);
assure(in, "Poem.bin");
in.read(readData[0], STR_LEN);
assert(strcmp(readData[0], "Hickory dickory dus. . .")
== 0);
// Seek -STR_LEN bytes from the end of file
in.seekg(-STR_LEN, ios::end);
in.read(readData[1], STR_LEN);
assert(strcmp(readData[1], "There's plenty more for us!")
== 0);
// Absolute seek (like using operator[] with a file)
in.seekg(3 * STR_LEN);
in.read(readData[2], STR_LEN);
assert(strcmp(readData[2], "That's just too bad,") == 0);
// Seek backwards from current position
in.seekg(-STR_LEN * 2, ios::cur);
in.read(readData[3], STR_LEN);
assert(strcmp(readData[3], "Well, if you have,") == 0);
// Seek from the begining of the file
in.seekg(1 * STR_LEN, ios::beg);
in.read(readData[4], STR_LEN);
assert(strcmp(readData[4], "Are you tired of C++?")
== 0);
} ///:~
This program writes a (very clever?) poem to a file using a binary output stream. Since we reopen it as an ifstream, we use seekg( )to position the "get pointer." As you can see, you can seek from the beginning or end of the file or from the current file position. Obviously, you must provide a positive number to move from the beginning of the file and a negative number to move back from the end .
Now that you know about the streambufand how to seek, you can understand an alternative method (besides using an fstreamobject) for creating a stream object that will both read and write a file. The following code first creates an ifstreamwith flags that say it’s both an input and an output file. You can’t write to an ifstream, of course, so you need to create an ostreamwith the underlying stream buffer: .
ifstream in("filename", ios::in | ios::out);
ostream out(in.rdbuf());
You might wonder what happens when you write to one of these objects. Here’s an example: .
//: C04:Iofile.cpp
// Reading & writing one file
#include
#include
#include "../require.h"
using namespace std;
int main() {
ifstream in("Iofile.cpp");
assure(in, "Iofile.cpp");
ofstream out("Iofile.out");
assure(out, "Iofile.out");
out << in.rdbuf(); // Copy file
in.close();
out.close();
// Open for reading and writing:
ifstream in2("Iofile.out", ios::in | ios::out);
assure(in2, "Iofile.out");
ostream out2(in2.rdbuf());
cout << in2.rdbuf(); // Print whole file
out2 << "Where does this end up?";
out2.seekp(0, ios::beg);
out2 << "And what about this?";
in2.seekg(0, ios::beg);
Читать дальше