C++ Primer 读书笔记 第八章 some tips about The IO library

1IO类:

IO 类型在三个独立的头文件中定义:iostream 定义读写控制窗口的类型,fstream 定义读写已命名文件的类型,而 sstream 所定义的类型则用于读写存储在内存中的 string 对象。

标准库类型不允许做复制或赋值操作。

这个要求有两层特别重要的含义。正如在第九章看到的,只有支持复制的元素类型可以存储在 vector 或其他容器类型里。由于流对象不能复制,因此不能存储在 vector(或其他)容器中(即不存在存储流对象的 vector 或其他容器)。

第二个含义是:形参或返回类型也不能为流类型。如果需要传递或返回 IO 对象,则必须传递或返回指向该对象的指针或引用.

一般情况下,如果要传递 IO 对象以便对它进行读写,可用非 const 引用的方式传递这个流对象。对 IO 对象的读写会改变它的状态,因此引用必须是非 const 的。

2IO 标准库的条件状态

strm::iostate

Name of the machine-dependent integral type, defined by each iostream class that is used to define the condition states.

机器相关的整型名,由各个 iostream 类定义,用于定义条件状态

strm::badbit

strm::iostate value used to indicate that a stream is corrupted.

strm::iostate 类型的值,用于指出被破坏的流

strm::failbit

strm::iostate value used to indicate that an IO operation failed.

strm::iostate 类型的值,用于指出失败的 IO 操作

strm::eofbit

strm::iostate value used to indicate the a stream hit end-of-file.

strm::iostate 类型的值,用于指出流已经到达文件结束符

s.eof()

true if eofbit in the stream s is set.

如果设置了流 s eofbit 值,则该函数返回 true

s.fail()

true if failbit in the stream s is set.

如果设置了流 s failbit 值,则该函数返回 true

s.bad()

true if badbit in the stream s is set.

如果设置了流 s badbit 值,则该函数返回 true

s.good()

true if the stream s is in a valid state.

如果流 s 处于有效状态,则该函数返回 true

s.clear()

Reset all condition values in the stream s to valid state.

将流 s 中的所有状态值都重设为有效状态

s.clear(flag)

Set specified condition state(s) in s to valid. Type of flag is strm::iostate.

将流 s 中的某个指定条件状态设置为有效。flag 的类型是 strm::iostate

s.setstate(flag)

Add specified condition to s. Type of flag is strm::iostate.

给流 s 添加指定条件。flag 的类型是 strm::iostate

s.rdstate()

Returns current condition of s as an strm::iostate value.

返回流 s 的当前条件,返回值类型为 strm::iostate

 

所有流对象都包含一个条件状态成员,该成员由 setstate clear 操作管理。这个状态成员为 iostate 类型,这是由各个 iostream 类分别定义的机器相关的整型。该状态成员以二进制位(bit)的形式使用,类似于第 5.3.1 节的例子中用于记录测验成绩的 int_quiz1 变量。

每个 IO 类还定义了三个 iostate 类型的常量值,分别表示特定的位模式。这些常量值用于指出特定类型的 IO 条件,可与位操作符一起使用,以便在一次操作中检查或设置多个标志。badbit 标志着系统级的故障,如无法恢复的读写错误。如果出现了这类错误,则该流通常就不能再继续使用了。如果出现的是可恢复的错误,如在希望获得数值型数据时输入了字符,此时则设置 failbit 标志,这种导致设置 failbit 的问题通常是可以修正的。eofbit 是在遇到文件结束符时设置的,此时同时还设置了 failbit

clear setstate 操作用于改变条件成员的状态。clear 操作将条件重设为有效状态。在流的使用出现了问题并做出补救后,如果我们希望把流重设为有效状态,则可以调用 clear 操作。使用 setstate 操作可打开某个指定的条件,用于表示某个问题的发生。除了添加的标记状态,setstate 将保留其他已存在的状态变量不变。

http://hi.baidu.com/jrckkyy/blog/item/ee657b17e49b5703c83d6df7.html

3.输出缓冲区的管理

系统将字符串字面值存储在与流 os 关联的缓冲区中。下面几种情况将导致缓冲区的内容被刷新,即写入到真实的输出设备或者文件:

程序正常结束。作为 main 返回工作的一部分,将清空所有输出缓冲区。

在一些不确定的时候,缓冲区可能已经满了,在这种情况下,缓冲区将会在写下一个值之前刷新。

用操纵符显式地刷新缓冲区,例如行结束符 endl

在每次输出操作执行完后,用 unitbuf 操作符设置流的内部状态,从而清空缓冲区。

可将输出流与输入流关联(tie)起来。在这种情况下,在读输入流时将刷新其关联的输出缓冲区。

1)输出缓冲区的刷新:

我们的程序已经使用过 endl 操纵符,用于输出一个换行符并刷新缓冲区。除此之外,C++ 语言还提供了另外两个类似的操纵符。第一个经常使用的 flush,用于刷新流,但不在输出中添加任何字符。第二个则是比较少用的 ends,这个操纵符在缓冲区中插入空字符 null,然后后刷新它:

    cout << "hi!" << flush;      // flushes the buffer; adds no data

    cout << "hi!" << ends;       // inserts a null, then flushes the buffer

    cout << "hi!" << endl;       // inserts a newline, then flushes the buffer

如果需要刷新所有输出,最好使用 unitbuf 操纵符。这个操纵符在每次执行完写操作后都刷新流:

    cout << unitbuf << "first" << " second" << nounitbuf;

等价于:

    cout << "first" << flush << " second" << flush;

nounitbuf 操纵符将流恢复为使用正常的、由系统管理的缓冲区刷新方式。

如果程序崩溃,则不会刷新缓冲区。

调试程序时,必须保证期待写入的每个输出都确实被刷新了。因为系统不会在程序崩溃时自动刷新缓冲区,这就可能出现这样的情况:程序做了写输出的工作,但写的内容并没有显示在标准输出上,仍然存储在输出缓冲区中等待输出。

2)将输出输入绑定在一起:

当输入流与输出流绑在一起时,任何读输入流的尝试都将首先刷新其输出流关联的缓冲区。标准库将 cout cin 绑在一起,因此语句:

 cin >> ival;

导致 cout 关联的缓冲区被刷新。

交互式系统通常应确保它们的输入和输出流是绑在一起的。这样做意味着可以保证任何输出,包括给用户的提示,都在试图读之前输出。

tie 函数可用 istream ostream 对象调用,使用一个指向 ostream 对象的指针形参。调用 tie 函数时,将实参流绑在调用该函数的对象上。如果一个流调用 tie 函数将其本身绑在传递给 tie ostream 实参对象上,则该流上的任何 IO 操作都会刷新实参所关联的缓冲区。

cin.tie(&cout);   // illustration only: the library ties cin and cout for us

    ostream *old_tie = cin.tie();

    cin.tie(0); // break tie to cout, cout no longer flushed when cin is read

    cin.tie(&cerr);   // ties cin and cerr, not necessarily a good idea!

    // ...

    cin.tie(0);       // break tie between cin and cerr

    cin.tie(old_tie); // restablish normal tie between cin and cout

4.文件的输入和输出:

文件流对象的初始化:

方式1

// construct an ifstream and bind it to the file named ifile

    ifstream infile(ifile.c_str());

    // ofstream output file object to write file named ofile

    ofstream outfile(ofile.c_str());

上述代码定义并打开了一对 fstream 对象。infile 是读的流,而 outfile 则是写的流。为 ifstream 或者 ofstream 对象提供文件名作为初始化式,就相当于打开了特定的文件。

方式2

ifstream infile;    // unbound input file stream

    ofstream outfile;   // unbound output file stream

infile.open("in");   // open file named "in" in the current directory

    outfile.open("out"); // open file named "out" in the current directory

上述语句将 infile 定义为读文件的流对象,将 outfile 定义为写文件的对象。这两个对象都没有捆绑具体的文件。在使用 fstream 对象之前,还必须使这些对象捆绑要读写的文件。

打开文件后需检查打开是否成功,这是一个好习惯。

if (!infile) {

        cerr << "error: unable to open input file: "

             << ifile << endl;

        return -1;

    }

fstream 对象一旦打开,就保持与指定的文件相关联。如果要把 fstream 对象与另一个不同的文件关联,则必须先关闭(close)现在的文件,然后打开(open)另一个文件:要点是在尝试打开新文件之前,必须先关闭当前的文件流。open 函数会检查流是否已经打开。如果已经打开,则设置内部状态,以指出发生了错误。接下来使用文件流的任何尝试都会失败。

     ifstream infile("in");      // opens file named "in" for reading

     infile.close();             // closes "in"

     infile.open("next");        // opens file named "next" for reading

如果打算重用已存在的流对象,那么 while 循环必须在每次循环进记得关闭(close)和清空(clear)文件流:

    ifstream input;

    vector<string>::const_iterator it = files.begin();

    //   for each file in the vector

    while (it != files.end()) {

        input.open(it->c_str());  // open the file

        // if the file is ok, read and "process" the input

        if (!input)

            break;                    // error: bail out!

        while(input >> s) // do the work on this file

            process(s);

        input.close();        // close file when we're done with it

        input.clear();        // reset state to ok

        ++it;                 // increment iterator to get next file

    }

5.文件模式:

8.3 文件模式

in

open for input

打开文件做读操作

out

open output

打开文件做写操作

app

seek to the end before every write

在每次写之前找到文件尾

ate

seek to the end immediately after the open

打开文件后立即将文件定位在文件尾

trunc

truncate an existing stream when opening it

打开文件时清空已存在的文件流

binary

do IO operations in binary mode

以二进制模式进行 IO 操作

outtrunc app 模式只能用于指定与 ofstream fstream 对象关联的文件;in 模式只能用于指定与 ifstream fstream 对象关联的文件。所有的文件都可以用 ate binary 模式打开。ate 模式只在打开时有效:文件打开后将定位在文件尾。以 binary 模式打开的流则将文件以字节序列的形式处理,而不解释流中的字符。

默认时,与 ifstream 流对象关联的文件将以 in 模式打开,该模式允许文件做读的操作:与 ofstream 关联的文件则以 out 模式打开,使文件可写。以 out 模式打开的文件会被清空:丢弃该文件存储的所有数据。

outfile2 的定义使用了按位或操作符将相应的文件同时以 out trunc 模式打开。

6stringstream

有些处理基于每行实现,而其他处理则要操纵每行中每个单词。可用 stringstreams 对象实现:

    string line, word;      // will hold a line and word from input, respectively

    while (getline(cin, line))   {            // read a line from the input into line

       // do per-line processing

       istringstream stream(line);            // bind to stream to the line we read

       while (stream >> word){          // read a word from line

           // do per-word processing

       }

    }

7. stringstream 提供的转换和/或格式化

stringstream 对象的一个常见用法是,需要在多种数据类型之间实现自动格式化时使用该类类型。例如,有一个数值型数据集合,要获取它们的 string 表示形式,或反之。sstream 输入和输出操作可自动地把算术类型转化为相应的 string 表示形式,反过来也可以。

    int val1 = 512, val2 = 1024;

    ostringstream format_message;

    // ok: converts values to a string representation

    format_message << "val1: " << val1 << "/n"

                   << "val2: " << val2 << "/n";

这里创建了一个名为 format_message ostringstream 类型空对象,并将指定的内容插入该对象。重点在于 int 型值自动转换为等价的可打印的字符串。format_message 的内容是以下字符:

val1: 512/nval2: 1024

相反,用 istringstream string 对象,即可重新将数值型数据找回来。读取 istringstream 对象自动地将数值型数据的字符表示方式转换为相应的算术值。

   // str member obtains the string associated with a stringstream

   istringstream input_istring(format_message.str());

   string dump; // place to dump the labels from the formatted message

   // extracts the stored ascii values, converting back to arithmetic types

   input_istring >> dump >> val1 >> dump >> val2;

   cout << val1 << " " << val2 << endl;  // prints 512 1024

这里使用 。str 成员获取与之前创建的 ostringstream 对象关联的 string 副本。再将 input_istring string 绑定起来。在读 input_istring 时,相应的值恢复为它们原来的数值型表示形式

为了读取 input_string,必须把该 string 对象分解为若干个部分。我们要的是数值型数据;为了得到它们,必须读取(和忽略)处于所需数据周围的标号。

(不理解)

 

 

 

 

 

 

 

你可能感兴趣的:(C++ Primer 读书笔记 第八章 some tips about The IO library)