File: readwrite.yo

package info (click to toggle)
c%2B%2B-annotations 13.02.02-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 13,576 kB
  • sloc: cpp: 25,297; makefile: 1,523; ansic: 165; sh: 126; perl: 90; fortran: 27
file content (149 lines) | stat: -rw-r--r-- 8,215 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
Streams can be read em(and) written 
    hi(stream: read and write) using hi(iostream)tt(std::iostream)
objects. Commonly encountered are hi(fstream)tt(std::fstream) objects and
sometimes hi(stringstream)tt(std::stringstream) objects. Other types of
readable and writable streams can be defined, by deriving such streams from
the tt(std::iostream) class (cf. chapter ref(POLYMORPHISM), in particular its
section ref(IOSTREAMBUF)). 

In this section we concentrate on the tt(std::fstream) class.  As with
tt(ifstream) and tt(ofstream) objects, the tt(fstream) constructor expects the
name of the file to be opened:
        verb(        fstream inout("iofile", ios::in | ios::out);)

Note the use of the constants hi(in)tt(ios::in) and hi(out)tt(ios::out),
indicating that the file must be opened for both reading and writing. Multiple
mode indicators may be used, concatenated by the tt(bitor) operator.
Alternatively, instead of tt(ios::out), hi(app)tt(ios::app) could have been
used and mere writing would become appending (at the end of the file).

    Reading and writing to the same stream is always a bit awkward: what to do
when the stream may not yet exist, but if it already exists it should not
be rewritten? To realize this the following approach can be used:
    verbinclude(-a examples/existingreadwrite.cc)
    Under this approach if the construction fails tt(fname) didn't yet
exist. But then, after clearing the failure flag, tt(open) is used also
specifying the hi(trunc)tt(ios::trunc) flag: this creates an empty file, but
because of tt(ios::in) the file is also readable.  In addition
hi(ate)tt(ios::ate) could be specified, ensuring that the initial read/write
action would by default occur at endOfFile().

Under hi(MS-Windows) hi(DOS) bf(DOS)-like operating systems that use the
multiple character sequence tt(\r\n) to separate lines in i(text files) the
flag hi(binary)tt(ios::binary) is required to process i(binary file)s ensuring
that tt(\r\n) combinations are processed as two characters. In general,
tt(ios::binary) should be specified when binary (non-text) files are to be
processed. By default files are opened as text files. i(Unix) operating
systems do not distinguish text files from binary files.

With tt(fstream) (in general: tt(iostream)) objects, combinations of file
flags are used to make sure that a stream is or is not (re)created empty when
opened. See section ref(OUTPUTMODES) for details.

    Once a file has been opened in read and write mode, the lshift() operator
can be used to insert information into the file, while the rshift() operator
may be used to extract information from the file. These operations may be
performed in any order, but a tt(seekg) or tt(seekp) operation is required
when switching between insertions and extractions. The seek operation is used
to activate the stream's data used for reading or those used for writing (and
em(vice versa)). The tt(istream) and tt(ostream) parts of tt(fstream) objects
share the stream's data buffer and by performing the seek operation the stream
either activates its tt(istream) or its tt(ostream) part. If the seek is
omitted, reading after writing and writing after reading simply fails. The
example shows a whitespace-delimited word being read from a file, writing
another string to the file, just beyond the point where the just read word
terminated. Finally yet another string is read which is found just beyond the
location where the just written strings ended:
        verb(    fstream f("filename", ios::in | ios::out);
    string  str;

    f >> str;       // read the first word

                    // write a well-known text
    f.seekp(0, ios::cur);
    f << "hello world";

    f.seekg(0, ios::cur);
    f >> str;       // and read again)

Since a em(seek) or em(clear) operation is required when alternating
between read and write (extraction and insertion) operations on the same file
it is not possible to execute a series of lshift() and rshift() operations in
one expression statement.

Of course, random insertions and extractions are hardly ever used. Generally,
insertions and extractions occur at well-known locations in a file.  In those
cases, the position where insertions or extractions are required can be
controlled and monitored by the tt(seekg), tt(seekp, tellg) and tt(tellp)
members (see sections ref(OSTREAMPOS) and ref(ISTREAMPOS)).

Error conditions (see section ref(IOSTATES)) occurring due to, e.g., reading
beyond end of file, reaching end of file, or positioning before begin of file,
can be cleared by the tt(clear) member function.  Following tt(clear)
processing may continue. E.g.,
        verb(    fstream f("filename", ios::in | ios::out);
    string  str;

    f.seekg(-10);   // this fails, but...
    f.clear();      // processing f continues

    f >> str;       // read the first word)

A situation where files are both read and written is seen in
    em(database) applications, using files consisting of records having fixed
sizes, and where locations and sizes of pieces of information are known. For
example, the following program adds text lines to a (possibly existing)
file. It can also be used to retrieve a particular line, given its
order-number in the file. A emi(binary file) tt(index) allows for the quick
retrieval of the location of lines.
        verbinclude(-a examples/readwrite.cc)
    Another example showing reading em(and) writing of files is provided by
the next program. It also illustrates the processing of NTBSs:
        verbinclude(-a examples/asciiz.cc)

    A completely different way to read and write streams may be implemented
using tt(streambuf) members. All considerations mentioned so far remain valid
(e.g., before a read operation following a write operation tt(seekg) must be
used). When  tt(streambuf) objects are used, either an
tt(istream) is associated with the tt(streambuf) object of another tt(ostream)
object, or an tt(ostream) object is associated with the
tt(streambuf) object of another tt(istream) object. Here is the previous
program again, now using
    hi(stream: associating) em(associated streams):
        verbinclude(-a examples/readwrite2.cc)
    In this example
    itemization(
    it() the streams associated with the tt(streambuf) objects of existing
streams are not ti(ifstream) or ti(ofstream) objects but basic ti(istream) and
ti(ostream) objects.
    it() The tt(streambuf) object is not defined by an tt(ifstream) or
tt(ofstream) object. Instead it is defined outside of the streams, using
a tt(filebuf) (cf. section ref(FILEBUF)) and constructions like:
        verb(filebuf fb("index", ios::in | ios::out | ios::trunc);
istream index_in(&fb);
ostream index_out(&fb);)

it() An tt(ifstream) object can be constructed using stream modes normally
used with tt(ofstream) objects. Conversely, an tt(ofstream) objects can be
constructed using stream modes normally used with tt(ifstream) objects.
    it() If tt(istream) and tt(ostreams) share a tt(streambuf), then their
read and write pointers (should) point to the shared buffer: they are tightly
coupled. However, instead of using two objects, defining/using a tt(iostream)
object receiving the tt(streambuf) automatically ensures that positioning for
reading and writing is synchronized (see also section ref(IOSTREAMBUF)).
    it() The advantage of using an external (separate) tt(streambuf) used by
an tt(iostream) object over using a predefined tt(fstream) object is that the
stream doesn't have to be a named file (see also section ref(STREAMBUF)).
    )

Like tt(fstream) objects string-stream objects can also be used for reading
and writing. After including the tthi(sstream) header file a
hi(stringstream)tt(std::stringstream) can be defined which supports both
reading and writing. After inserting information into a tt(stringstream)
object tt(seekg(0)) can be called to read its info from the beginning of its
content. When a tt(stringstream) must repeatedly be used for reading and
writing call its tt(clear) and tt(str) members before starting a new writing
cycle. Alternatively, a tt(stringstream str) can be reinitialized using tt(str
= stringstream{}). Here is an example:
        verbinclude(-as4 examples/stringstream.cc)