C++primer第八章 IO库 8.2 文件输入输出

8.2文件输入输出

  • 头文件fstream定义了三个类型来支持文件IO:ifstream从一个给定文件读取数据,ofstream向一个给定文件写入数据,以及fstream可以读写给定文件。在17.5.3节中(第676页)我们将介绍如何对同一个文件流既读又写。
  • 这些类型提供的操作与我们之前已经使用过的对象cin和cout的操作一样。特别是,我们可以用IO运算符(<<和>>)来读写文件,可以用getline(参见3.2.2节,第79页)从一个ifstream读取数据,包括8.1节中(第278页)介绍的内容也都适用于这些类型。
  • 除了继承自iostream类型的行为之外,fstream中定义的类型还增加了一些新的成员来管理与流关联的文件。在表8.3中列出了这些操作,我们可以对fstream,ifstream和ofstream对象调用这些操作,但不能对其他IO类型调用这些操作。

8.2.1使用文件流对象

  • 当我们想要读写一个文件时,可以定义一个文件流对象,并将对象与文件关联起来。每个文件流类都定义了一个名为open的成员函数,它完成一些系统相关的操作,来定位给定的文件,并视情况打开为读或写模式
  • 创建文件流对象时,我们可以提供文件名(可选的)。如果提供了一个文件名,则open会自动被调用:
  • ifstreamin(ifile);//构造一个ifstream并打开给定文件
  • ofstream out;//输出文件流未关联到任何文件
  • 这段代码定义了一个输入流in,它被初始化为从文件读取数据,文件名由string类型的参数ifile指定。第二条语句定义了一个输出流out,未与任何文件关联。在新C++重标准中,文件名既可以是库类型string对象,也可以是C风格字符数组(参见3.5.4节,1第109页)。旧版本的标准库只允许C风格字符数组。

用fstream代替iostream&

  • 在8.1节(第279页)已经提到过,在要求使用基类型对象的地方,我们可以用继承类型的对象来替代。这意味着,接受一个iostream类型引用(或指针)参数的函数,可以用一个对应的fstream(或sstream)类型来调用。也就是说,如果有一个函数接受一个ostream&参数,我们在调用这个函数时,可以传递给它一个ofstream对象,对istream&和ifstream也是类似的。

成 员 函 数 open和 close

  • 如果我们定义了一个空文件流对象,可以随后调用open来将它与文件关联起来:
  • ifstream in(ifile);//构筑一个ifstream并打开给定文件
  • ofstream out;//输出文件流未与任何文件相关联
  • out.open(ifile+*'.copy");//打开指定文件
  • 如果调用open失败,failbit会被置位(参见8.1.2节,第280页)。因为调用open可能失败,进行Open是否成功的检测通常是一个好习惯:
  • if(out)//检查open是否成功
  • //open成功,我们可以使用文件了
  • 这个条件判断与我们之前将cin用作条件相似。如果open失败,条件会为假,我们就不会去使用out了。
  • 一旦一个文件流已经打开,它就保持与对应文件的关联。实际上,对一个已经打开的文件流调用open会失败,并会导致failbit被置位。随后的试图使用文件流的操作都会失败。为了将文件流关联到另外一个文件,必须首先关闭已经关联的文件。一旦文件成功关闭,我们可以打开新的文件:
  • in.close();//关闭文件
  • in.open(ifile+“2”);//打开另一个文件如果open成功,则open会设置流的状态,使得good()为true。

自动构造和析构

  • 考虑这样一个程序,它的main函数接受一个要处理的文件列表(参见6.2.5节,第】96页)。这种程序可能会有如下的循环:
  • //对每个传递给程序的文件执行循环操作
//对每个传递给程序的文件执行循环操作
    for (auto p = argv + 1; p < argv + argc; ++p) {
        std::ifstream input(*p); //创建输出流并且打开文件
        if (input){              //如果文件打开成功,“处理”这个文件
            //process(input);  
        } else{
            std::cerr << "couldn‘t open: " + std::string(*p);
        }
    }//每个循环步input都会离开作用域,因此会被销毁
  • 每个循环步构造一个新的名为input的ifstream对象,并打开它来读取给定的文件。像之前一样,我们检查open是否成功。如果成功,将文件传递给一个函数,该函数负责读取并处理输入数据。如果open失败,打印一条错误信息并继续处理下一个文件。因为input是while循环的局部变量,它在每个循环步中都要创建和销毁一次(参见5.4.1节,第165页)。当一个fstream对象离开其作用域时,与之关联的文件会自动关闭。在下一步循环中,input会再次被创建。
  • 当一个fstream对象被销毁时,close会自动被调用

8 .2 .2 文件模式

  • 每个流都有一个关联的文件模式(file mode),用来指出如何使用文件。表 8.4列出了 文件模式和它们的含义。

  • 无论用哪种方式打开文件,我们都可以指定文件模式,调用。pen打开文件时可以,用一个文件名初始化流来隐式打开文件时也可以。指定文件模式有如下限制:
  • 只可以对ofstream或fstream对象设定out模式
  • 只可以对ifstream或fstream对象设定in模式
  • 只有当out也被设定时才可设定trunc模式
  • 只要trunc没被设定,就可以设定app模式。在app模式下,即使没有显式指定out模式,文件也总是以输出方式被打开。
  • 默认情况下,即使我们没有指定trunc,以out模式打开的文件也会被截断。为了保留以out模式打开的文件的内容,我们必须同时指定app模式,这样只会将数据追加写到文件末尾;或者同时指定in模式,即打开文件同时进行读写操作(参见17.5.3节,第676页,将介绍对同一个文件既进行输入又进行输出的方法)。
  • ate和binary模式可用于任何类型的文件流对象,且可以与其他任何文件模式组合使用。
  • 每个文件流类型都定义了一个默认的文件模式,当我们未指定文件模式时,就使用此默认模式。与ifstream关联的文件默认以in模式打开;与ofstream关联的文件默认以out模式打开;与fstream关联的文件默认以in和out模式打开。

以out模式打开文件会丢弃已有数据

  • 默认情况下,当我们打开一个ofstmam时,文件的内容会被丢弃。阻止一个ofstream清空给定文件内容的方法是同时指定app模式
  • //在这几条语句中,filel都被截断
  • ofstream out("file1");//隐含以输出模式打开文件并截断文件
  • ofstream out2("file1",ofstream::out);//隐含地截断文件
  • ofstreamout3("file1",ofstream::out|ofstream::trunc);
  • //为了保留文件内容,我们必须显式指定app模式
  • ofstream app("file2”,ofstream::app);//隐含为输出模式
  • ofstreamapp2(nfile2n,ofstream::out|ofstream::app);
  • 保留被ofstream打开的文件中已有数据的唯一方法是显式指定app或 in 模式

每次调用open时都会确定文件模式

  • 对于一个给定流,每当打开文件时,都可以改变其文件模式。
  • ofstreamout;//未指定文件打开模式
  • out.open(^scratchpad");//模式隐合设置为输出和截断
  • out.close();//关闭out,以便我们将其用于其他文件
  • out.open("precious",ofstream::app);//模式为输出和追加
  • out.close();
  • 第一个open调用未显式指定输出模式,文件隐式地以out模式打开。通常情况下,out模式意味着同时使用trunc模式。因此,当前目录下名为scratchpad的文件的内容将被清空。当打开名为precious的文件时,我们指定了append模式(app)。文件中已有的数据都得以保留,所有写操作都在文件末尾进行。
  • 在每次打开文件时,都要设置文件模式,可能是显式地设置,也可能是隐式地也设置当程序未指定模式时,就使用默认值。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值