📄 chap05.htm
字号:
<font color=#0000ff>int</font> main() {
ifstream in(<font color=#004488>"Stype.cpp"</font>);
assure(in, <font color=#004488>"Stype.cpp"</font>);
cout << in.rdbuf(); <font color=#009900>// Outputs entire file</font>
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">An <B>ifstream</B>
<A NAME="Index275"></A>is created using the source code file for this program
as an argument. The <B>assure( ) </B> will report a failure if the file cannot
be opened. All the work really happens in the statement:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>cout << in.rdbuf();</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">which causes the entire contents of the
file to be sent to <B>cout</B>. This is not only more succinct to code, it is
often more efficient than moving the bytes one at a
time.</FONT><A NAME="_Toc312373884"></A><A NAME="_Toc519041952"></A><BR></P></DIV>
<A NAME="Heading120"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
Using get( ) with a streambuf</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">There is a form of
<B>get( )<A NAME="Index276"></A><A NAME="Index277"></A></B> that allows you
to write directly into the <B>streambuf</B> of another object. The first
argument is the destination <B>streambuf</B> (whose address is mysteriously
taken using a <I>reference</I>, discussed in Chapter XX), and the second is the
terminating character, which stops the <B>get( )</B> function. So yet
another way to print a file to standard output is</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C05:Sbufget.cpp</font>
<font color=#009900>// Get directly into a streambuf</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
<font color=#009900>//{-g++295}</font>
#include <font color=#004488>"..</font><font color=#004488>/require.h"</font>
#include <fstream>
#include <iostream>
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
<font color=#0000ff>int</font> main() {
ifstream in(<font color=#004488>"Sbufget.cpp"</font>);
assure(in, <font color=#004488>"Sbufget.cpp"</font>);
<font color=#0000ff>while</font>(in.get(*cout.rdbuf()))
in.ignore();
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia"><B>rdbuf( )</B> returns a pointer,
so it must be dereferenced to satisfy the function’s need to see an
object. The <B>get( )</B> function, remember, doesn’t pull the
terminating character from the input stream, so it must be removed using
<B>ignore( )</B> so <B>get( )</B> doesn’t just bonk up against
the newline forever (which it will, otherwise).</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You probably won’t need to use a
technique like this very often, but it may be useful to know it
exists.</FONT><A NAME="_Toc305628667"></A><A NAME="_Toc312373885"></A><A NAME="_Toc519041953"></A><BR></P></DIV>
<A NAME="Heading121"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Seeking in iostreams<BR><A NAME="Index278"></A><A NAME="Index279"></A></H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Each type of iostream has a concept of
where its “next” character will come from (if it’s an
<B>istream</B>) or go (if it’s an <B>ostream</B>). In some situations you
may want to move this stream position. You can do it using two models: One uses
an absolute location in the stream called the
<B>streampos<A NAME="Index280"></A></B>; the second works like the Standard C
library functions
<B>fseek( )<A NAME="Index281"></A><A NAME="Index282"></A></B> for a file
and moves a given number of bytes from the beginning, end, or current position
in the file.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <B>streampos</B> approach requires
that you first call a “tell” function:
<B>tellp( )<A NAME="Index283"></A><A NAME="Index284"></A></B> for an
<B>ostream</B> or
<B>tellg( )<A NAME="Index285"></A><A NAME="Index286"></A></B> for an
<B>istream</B>. (The “p” refers to the “put
pointer”<A NAME="Index287"></A> and the “g” refers to the
“get pointer.”) This function returns a <B>streampos</B> you can
later use in the single-argument version of
<B>seekp( )<A NAME="Index288"></A><A NAME="Index289"></A></B> for an
<B>ostream</B> or
<B>seekg( )<A NAME="Index290"></A><A NAME="Index291"></A></B> for an
<B>istream</B>, when you want to return to that position in the
stream.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The second approach is a relative seek
and uses overloaded versions of <B>seekp( )</B> and <B>seekg( )</B>.
The first argument is the number of bytes to move: it may be positive or
negative. The second argument is the seek direction:</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><TABLE BORDER>
<TR VALIGN="TOP">
<TD>
<DIV ALIGN="CENTER"><FONT FACE="Georgia">ios::beg</FONT><BR></P></DIV>
</TD>
<TD>
<DIV ALIGN="CENTER"><FONT FACE="Georgia">From beginning of
stream</FONT><BR></P></DIV>
</TD>
</TR>
<TR VALIGN="TOP">
<TD>
<DIV ALIGN="CENTER"><FONT FACE="Georgia">ios::cur</FONT><BR></P></DIV>
</TD>
<TD>
<DIV ALIGN="CENTER"><FONT FACE="Georgia">Current position in
stream</FONT><BR></P></DIV>
</TD>
</TR>
<TR VALIGN="TOP">
<TD>
<DIV ALIGN="CENTER"><FONT FACE="Georgia">ios::end</FONT><BR></P></DIV>
</TD>
<TD>
<DIV ALIGN="CENTER"><FONT FACE="Georgia">From end of stream</FONT><BR></P></DIV>
</TD>
</TR>
<A NAME="Index292"></A><A NAME="Index293"></A><A NAME="Index294"></A></TABLE></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">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 <B>cstdio</B>. With C++, you can seek in any
type of iostream (although the behavior of <B>cin</B> & <B>cout</B> when
seeking is undefined):</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C05:Seeking.cpp</font>
<font color=#009900>// Seeking in iostreams</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
#include <font color=#004488>"..</font><font color=#004488>/require.h"</font>
#include <iostream>
#include <fstream>
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
<font color=#0000ff>int</font> main() {
ifstream in(<font color=#004488>"Seeking.cpp"</font>);
assure(in, <font color=#004488>"Seeking.cpp"</font>); <font color=#009900>// File must already exist</font>
in.seekg(0, ios::end); <font color=#009900>// End of file</font>
streampos sp = in.tellg(); <font color=#009900>// Size of file</font>
cout << <font color=#004488>"file size = "</font> << sp << endl;
in.seekg(-sp/10, ios::end);
streampos sp2 = in.tellg();
in.seekg(0, ios::beg); <font color=#009900>// Start of file</font>
cout << in.rdbuf(); <font color=#009900>// Print whole file</font>
in.seekg(sp2); <font color=#009900>// Move to streampos</font>
<font color=#009900>// Prints the last 1/10th of the file:</font>
cout << endl << endl << in.rdbuf() << endl;
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This program picks a file name off the
command line and opens it as an <B>ifstream</B>. <B>assert( ) </B>detects
an open failure. Because this is a type of <B>istream</B>, <B>seekg( )</B>
is used to position the “get pointer<A NAME="Index295"></A>.” The
first call seeks zero bytes off the end of the file, that is, to the end.
Because a <B>streampos</B> is a <B>typedef</B> for a <B>long</B>, calling
<B>tellg( )</B> at that point also returns the size of the file, which is
printed out. Then a seek is performed moving the get pointer 1/10 the size of
the file – notice it’s a negative seek from the end of the file, so
it backs up from the end. If you try to seek positively from the end of the
file, the get pointer will just stay at the end. The <B>streampos</B> at that
point is captured into <B>sp2</B>, then a <B>seekg( )</B> is performed back
to the beginning of the file so the whole thing can be printed out using the
<B>streambuf</B> pointer produced with <B>rdbuf( )</B>. Finally, the
overloaded version of <B>seekg( )</B> is used with the <B>streampos</B>
<B>sp2</B> to move to the previous position, and the last portion of the file is
printed
out.</FONT><A NAME="_Toc312373886"></A><A NAME="_Toc519041954"></A><BR></P></DIV>
<A NAME="Heading122"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
Creating read/write files</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Now that you know about the
<B>streambuf</B> and how to seek, you can understand how to create a stream
object that will both read and write a file. The following code first creates an
<B>ifstream</B> with flags that say it’s both an input and an output file.
The compiler won’t let you write to an <B>ifstream</B>, however, so you
need to create an <B>ostream</B> with the underlying stream
buffer:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE> ifstream in(<font color=#004488>"filename"</font>, ios::in|ios::out);
ostream out(in.rdbuf());</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You may wonder what happens when you
write to one of these objects. Here’s an example:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C05:Iofile.cpp</font>
<font color=#009900>// Reading & writing one file</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
#include <font color=#004488>"..</font><font color=#004488>/require.h"</font>
#include <iostream>
#include <fstream>
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
<font color=#0000ff>int</font> main() {
ifstream in(<font color=#004488>"Iofile.cpp"</font>);
assure(in, <font color=#004488>"Iofile.cpp"</font>);
ofstream out(<font color=#004488>"Iofile.out"</font>);
assure(out, <font color=#004488>"Iofile.out"</font>);
out << in.rdbuf(); <font color=#009900>// Copy file</font>
in.close();
out.close();
<font color=#009900>// Open for reading and writing:</font>
ifstream in2(<font color=#004488>"Iofile.out"</font>, ios::in | ios::out);
assure(in2, <font color=#004488>"Iofile.out"</font>);
ostream out2(in2.rdbuf());
cout << in2.rdbuf(); <font color=#009900>// Print whole file</font>
out2 << <font color=#004488>"Where does this end up?"</font>;
out2.seekp(0, ios::beg);
out2 << <font color=#004488>"And what about this?"</font>;
in2.seekg(0, ios::beg);
cout << in2.rdbuf();
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The first five lines copy the source code
for this program into a file called <B>iofile.out</B>, and then close the files.
This gives us a safe text file to play around with. Then the aforementioned
technique is used to create two objects that read and write to the same file. In
<B>cout << in2.rdbuf( )</B>, you can see the “get”
pointer is initialized to the beginning of the file. The “put”
pointer, however, is set to the end of the file because “Where does this
end up?” appears appended to the file. However, if the put pointer is
moved to the beginning with a <B>seekp( )</B>, all the inserted text
<I>overwrites </I>the existing text. Both writes are seen when the get pointer
is moved back to the beginning with a <B>seekg( )</B>, and the file is
printed out. Of course, the file is automatically saved and closed when
<B>out2</B> goes out of scope and its destructor is
called.</FONT><A NAME="_Toc305628668"></A><A NAME="_Toc312373887"></A><A NAME="_Toc519041955"></A><BR></P></DIV>
<A NAME="Heading123"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
stringstreams<A NAME="_Toc519041956"></A></H2></FONT>
<A NAME="Heading124"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
strstreams</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Before there were <B>stringstream</B>s,
there were the more primitive <B>strstream</B>s. Although these are not an
official part of Standard C++, they have been around a long time so compilers
will no do
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -