Lecture Notes for Advanced Programming II

29 September 2002 - Stream I-O


  1. a file is represented as a file stream inside a c++ program.

    1. a stream represents the file as an array

    2. the array is generic - char and wchar_t

    3. the array can change size, grow in particular

  2. there are many stream classes

    1. ifstream - file streams that read files

    2. ofstream - file streams that write files

    3. fstream - file streams that read and write files

    4. defined in the <fstream> include file

  3. opening and closing files

    1. the stream member function open() connects a file stream to a file

    2. void open(const char fname[])

    3. the file must exist

    4. the stream member function close() breaks the connection between a file stream and a file

    5. void close(void)

    6. file-stream instances going out of scope are closed automatically

      1. close them explicitly anyway

  4. reading and writing files

    1. another part of a file - the file pointer

      1. think of it as the current index

      2. reads and writes start at the file pointer

      3. reads and writes move the file pointer

    2. the stream member function void read(char data[], int data_size)

      1. read at most data_size bytes from the file stream into data

      2. reading begins at the file pointer

      3. file pointer moves to the next byte after the last byte read

      4. file data are unchanged

      5. input streams only

    3. the stream member function void write(const char data[], int data_size)

      1. write data_size bytes from data into the file stream

      2. writing begins at the file pointer

      3. file pointer moves to the next byte after the last byte written

      4. file data are changed

      5. output streams only

    4. sequential file i-o - march through the file byte-by-byte from start to finish without skipping bytes; all streams support sequential I-O

  5. the end-of-file (eof) condition

    1. what happens when the last byte is read

    2. the file pointer is one past the end of the file - the eof condition

    3. reading at eof does nothing - returns no data, leaves the file pointer unchanged

    4. the bool eof(void) stream member function returns true at eof, false otherwise

    5. you can't discover eof until you try to read - you can't tell if anybody's home until you knock on the door

      1. while (!inf.eof())
          inf.read(data, data_size);
        
        is wrong

      2. while (true) {
          inf.read(data, data_size);
          if (inf.eof()) break;
          }
        
        is right

      3. reading five bytes from a four byte file

        1. partial reads - reading fewer bytes than specified

        2. partial reads set the eof condition - trying to read the byte that doesn't exist

        3. the stream member function int gcount(void) returns the number of bytes last read

        4. be careful - partial reads don't necessarily indicate an eof condition

      4. none of this applies to writing files

  6. formatted vs. unformatted i-o

    1. unformatted i-o doesn't change the data being read or written

    2. formatted i-o changes the data being read or written

    3. why change - 3 is not the same as '3' or "3"

      1. humans understand with characters; machines understand with bits

      2. characters go to and come from humans

      3. but characters are bits - but bits of the wrong kind

      4. 3 = 0000000000000011 and '3' = 0000001100000011 = 51

      5. for humans to understand 3, it has to be output as '3' (or 51)

    4. how change - convert numbers to characters and vice versa

      1. the number 100 has to be changed into the characters '1', '0', and '0'

      2. the characters '5', '2', and '1' have to be converted into the number 512

    5. formatted i-o converts between numbers and characters in both directions

      1. not only numbers can be converted

      2. characters - not much of a conversion

      3. strings - ditto, no quotes

      4. booleans - 0 or 1, true or false

      5. even objects - user defined

  7. stream extraction (input) and insertion (output)

    1. the stream insertion operator outs << value

      1. outs is an io stream opened for writing

      2. value is a value of a type the insertion operator knows how to convert (int, char, string and so on)

      3. value is converted into characters

      4. the characters are appended to the stream at the file pointer

      5. the file pointer moves to the byte just after the last byte written

    2. the stream extraction operator ins >> var

      1. extraction is not as simple as insertion

      2. ins is an io stream opened for reading

      3. var is a variable having a type the extraction operator knows how to convert

      4. starting at the file pointer, extraction reads as many bytes as there are consistent with the type of value being read

        1. for integers - the characters '0' through '9' possibly proceeded by either '-' or '+'; all the digits are read, but not necessarily used

        2. for characters - the next bytes, single quotes not needed

        3. the file pointer points to the next byte after the last byte read

        4. the characters are converted to the proper value and assigned to var

      5. whitespace and stream extraction

        1. in general, stream extraction does not consider white-space characters as being part of any value, including strings

        2. white-space characters include space, tab, and newline

        3. initial whitespace is skipped

        4. trailing whitespace ends extraction

      6. extraction and insertion return the stream involved

        1. cascading insertions and extractions - cout << "i = " << i << "\n"

        2. if cin hits eof, it returns NULL - while (cin >> i)

    3. stream errors

      1. file io may fail for many reasons - error reporting is complex; dealing with errors is complex

      2. There are three error types

        1. eof - the end-of-file condition has been detected

        2. fail - non-fatal i-o error, usually a format error

        3. bad - a fatal error; undefined state

        4. each have tests - bool eof(void), and so on

      3. bool good(void) - true if no errors; false otherwise

        1. ifstream inf;
          const string fname = "my.dat";
          inf.open(fname.c_str());
          if (!inf.good())
            cerr << "Can't open " << fname << "\n";
          

        2. inf.read(data, data_size);
          if (inf.eof())
            // whatever
          if (!inf.good())
            // whatever
          

      4. bool operator!(stream) returns true if there are no errors

        1. operator! doesn't consider eof an error

        2. ifstream inf;
          const string fname = "my.dat";
          inf.open(fname.c_str());
          if (!inf)
            cerr << "Can't open " << fname << "\n";
          

      5. what's up with while (cin >> x) { ... }

        1. converting the stream to a void * pointer.

      6. prefer good() over operator!

      7. incorrect input

        1. if the input characters don't match the expected value, the extraction fails with a fail error

        2. the file pointer does not advance past the bad character - white space stays skipped over

        3. var does not receive a value

        4. good() returns false

  8. opening files

    1. a second argument to open() describes how the file should be opened

      1. ios::in - open for reading, file pointer at the beginning of the file

      2. ios::out - open for writing, file pointer at the beginning of the file; this trashes the previous file contents

      3. ios::app - open for writing (appending), file pointer at the end of the file; this preserves the previous contents of the file

      4. the default for ifstreams is ios::in

      5. the default for ofstreams is ios::out - the default open for writes is destructive

      6. fstreams have no defaults - you must specify ios::in, ios::out, or ios::in + ios::out

    2. default fstream constructors can take the same arguments as open()

      1. ifstream inf("my.dat");

  9. reading and writing

    1. the void put(char) file stream member function

      1. write a character into the file at the file pointer

      2. advance the file pointer by one

    2. the int get(void) file stream member function

      1. read and return the character from the file at the file pointer

      2. advance the file pointer by one

      3. return -1 at eof

    3. the istream getline(istream, string, char) function

      1. defined in <string>, not in the stream includes

      2. it's not a member function - no dot access

      3. reads the string up to but not including the delimiter or eof

        1. the delimiter is discarded - default delimiter is newline

        2. leading and intermediate white space is not ignored

  10. stream manipulators

    1. control how formatted i-o behaves on input and output

    2. defined in <iomanip>

    3. set the number base - hex, dec, oct

      1. int i = 135 ; cout << i << " in hex is " << hex << i << "\n"

      2. cout << "Input a hex number: " ; cin >> hex >> i

      3. base manipulators are sticky - the conversion remains once set

        1. this is a pain - some manipulators are not sticky

        2. this is also compiler dependent

      4. also the setbase(i) manipulator where i = 8, 10, or 16

    4. set the field width - setw(i)

      1. on output, use at least i characters to format

        1. cout << setw(5) << 3 produces " 3"

        2. extra characters are blanks, inserted to the left

        3. the full value is always output - no truncation, larger field

        4. cout << setw(1) << 123 produces "123"

      2. can also be used for input, but to what effect

      3. setw() is not sticky

        1. cout << setw(4) << "a" << "b" produces " ab"

        2. cout << setw(4) << "a" << setw(4) << "b" produces " a b"

    5. the setfill(c) manipulator - use character c as the pad

      1. cout << setw(5) << setfill('*') << 1 produces "****1"

      2. setfill() is sticky

    6. the setiosflags() manipulator - modify control bits

      1. ios::left - left justify output; "1 "

      2. ios::right - right justify output; " 1"

      3. ios::showpoint - output floating point with a dot and zeros

      4. ios::skipws - skip whitespace on input; also the ws manipulator; this usually doesn't do what you want

      5. ios::scientific - output floating point in scientific notation; also(ios::fixed

      6. ios::uppercase - output uppercase hex digits; also ios::lowercase

      7. these are sticky - undone by the resetiosflags() manipulator

    7. most manipulators are available as member functions too

      1. the setw() manipulator and the width() stream member function

      2. the setfill() manipulator and the fill() stream member function

      3. the setiosflags() manipulator and the setf() stream member function - also unsetf()

    8. other manipulators

      1. endl - output a newline

      2. flush - force output

  11. random access

    1. std::ios::pos_type tellg(void) and std::ios::pos_type tellp(void)

    2. values of type(pos_type) are not integers - you can't use them to find file size

    3. istream seekg(pos_type) and ostream seekp(pos_type) reposition the file pointer as indicated

    4. istream seekg(off_type seek_dir) and ostream seekp(off_type, seek_dir) reposition the file pointer relative to the indicated position

      1. positions are std::ios::beg, cur, and end.


This page last modified on 29 January 2002.