【C++ Primer】第八章 文件的输入输出

来源:互联网 发布:windows10还原网络设置 编辑:程序博客网 时间:2024/05/23 11:15

一、IO对象不可复制或赋值

出于某些原因,标准库类型不允许做复制或赋值操作。比如,

ofstream out1,out2;out1 = out2;   //error:cannot assign stream objects//print function: parameter is copiedofstream = print(ofstream);out2 = print(out2);    //error:cannot copy stream objects

1)只有支持复制的元素类型可以存储在vector或其他容器类型里。由于流对象不能复制,因此不能存储在vector(或其他)容器中(即不存在存储流对象的vector或其他容器)。

2)形参或返回类型也不能为流类型。如果需要传递或返回IO对象,则必须传递或返回指向该对象的指针或引用:

ofstream &print(ofstream&);      //ok:takes a reference, no copywhile (print(out2) )       {/*...*/}        //ok:pass reference to out2

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


二、流的条件状态

IO标准库管理一系列条件状态(condition state)成员,用来标记给定的IO对象是否处于可用状态。

  • s.eof()             end-of-file,文件结束符
  • s.good()            如果流s处于有效状态,则该函数返回true
  • s.clear()           将流s中的所有状态值都设为有效状态
  • s.clear(flag)       将流s中的某个指定条件状态设置为有效。flag的类型是strm::iostate
  • s.setstate(flag)    给流s添加指定条件。
  • s.rdstate()         返回流s的当前条件

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

    流的状态邮bad、fail、eof和good操作揭示。如果bad、fail或eof中的任一个为true,流本身将处于错误状态。

   1.条件状态的访问

    rdstate成员函数返回一个iostate类型的值,该值对应于流当前的整个条件状态:

//remenber current state of cinistream::iostate old_state = cin.rdstate();cin.clear();process_input();    //use cincin.clear(old_state);    //now reset cin to old state

三、输出缓冲区的管理

每个IO对象管理一个缓冲区,用于存储程序读写的数据。

os<<"please enter a value:";

系统将字符串字面值存储在与流os关联的缓冲区中。下面几种情况将导致缓冲区的内容被刷新:

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

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

    3)用操作符显式的刷新缓冲区,例如行结束符endl。

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

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

1.输出缓冲区的刷新(flush、ends、endl)

cout<<"hi"<<flush;   //flushes the buffer;adds no datacout<<"hi"<<ends;    //inserts a null,then flushes the buffercout<<"hi"<<endl;    //inserts a newline,then flushes the buffer

2.unitbuf操作符

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

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

等价于:

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

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

    note:程序崩溃后不会刷新缓冲区

四、文件的输入和输出

C++中的文件名:

    由于历史原因,IO标准库使用C风格字符串而不是C++ string类型的字符串作为文件名。在创建fstream对象时,如果调用open或使用文件名作初始化式,需要传递的实参应为C风格字符串,而不是标准库string对象。程序常常从标准输入获得文件名。通常,比较好的方法是将文件名读入string对象,而不是C风格字符数组。假设要使用的文件名保存在string对象中,则可调用c_str成员获取C风格字符串。

1.文件流对象的使用

    需要读写文件时,则必须定义自己的对象,并将它们绑定在需要的文件上。假设ifile和ofile是存储希望读写的文件名的string对象:

//construct an ifstream and bind it to the file named ifileifstream infile(ifile.c_str());//ofstream output file object to write file named ofileofstream outfile(ofile.c_str());

infile和ofile分别是读文件的流对象和写文件的流对象

以上是在定义的时候直接初始化打开一对fstream对象。若开始未初始化,如下:

ifstream infile;    //unbound input file streamofstream outfile;   //unbound output file stream

上面定义的两对象均未绑定具体文件。在使用fstream对象之前,还必须使这些对象捆绑要读写的文件:

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

调用open成员函数将已存在的fstream对象与特定文件绑定。

   将文件与新文件流重新绑定

ifstream infile("in");infile.close();infile.open("next");

在尝试打开新文件之前先关闭当前的文件流


五.字符串流

标准库string类型

#include <string>

using std::string;

string对象的定义和初始化

  • string s1;              默认构造函数,s1为空串
  • string s2(s1);          将s2初始化为s1的一个副本
  • string s3("value");     将s3初始化为一个字符串字面值副本
  • string s4(n,'c');       将s4初始化为字符'c'的n个副本

Note:因为历史原因以及为了与C语言兼容,标准库string类型和字符型字面值不是同一种类型

string对象的读写

cin>>s;

从标准输入读取string,并将读入的串存储在s中。string类型的输入操作符:

  • 读取并忽略开头所有的空白字符(如空格,换行符,制表符)。
  • 读取字符直至再次遇到空白字符,读取终止。

因此,如果输入到程序的是“   hello world!  ”,屏幕上将输出“hello”,而不含任何空格。

1.stringstream对象的使用

string line, word;      //will hold a line and word from input,respectivelywhile(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       }}
这里使用getline函数从输入读取整行内容。然后为了获得每行中的单词,将一个istringstream对象与所读取的行绑定起来,这样只需使用普通的string输入操作符即可读出每行中的单词。

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

int val1 = 512, val2 = 1024;ostringstream format_message;//ok:converts values to a string representationformat_message<<"val1: "<<val1<<"\n"              <<"val2: "<<val2<<"\n";

format_message里面的内容是以下字符:

val1: 512\nval2: 1024

用istringstream读string对象

      //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 stored ascii values,converting back to arithmetic types      input_istring>>dump>>val1>>dump>>val2;      cout<<val1<<" "<<val2<<endl;     //print 512 1024
这里使用str成员获取与之前创建的ostringstream对象关联的string副本,再将input_istring与string绑定起来。


C++使用标准库类处理输入和输出:

iostream类处理面向流的输入和输出。

fstream类处理已命名文件的IO。

stringstream类处理内存中字符串的IO。