C++PrimerPlus学习之输入,输出和文件

流和缓冲区

  • C++程序把输入和输出看作字节流。输入时,程序从输入流中抽取字节;输出时,程序将字节插入到输出流中。
  • 流充当了程序和流源或流目标之间的桥梁。C++程序只是检查字节流,而不需要知道字节来自何方和去向何处。
  • 使用缓冲区可以更高效地处理输入和输出。
    • 处理输入时,缓冲区通常从磁盘读取大量信息,然后每次从缓冲区里读取一个字节。
    • 处理输出时,程序首先先填满缓冲区,然后将整块数据传输给硬盘,并清空缓冲区,以备下一批输出使用。这被称为刷新缓冲区。但如果是通过键盘来输入的话,在这种情况下,C++程序通常在用户按下回车键时刷新输入缓冲区。
  • 流文件的关系图
    在这里插入图片描述
    • streambuf类为缓冲区提供了内存,并提供了用于填充缓冲区,访问缓冲区内容,刷新缓冲区和管理缓冲区内存的类方法
    • ios_base类表示流的一般特征,如是否可读取,是二进制还是文本流等
    • ios类基于ios_base,其中包括了一个指向streambuf对象的指针成员
    • ostream类是从ios类派生而来的,提供了输出方法
    • istream类是从ios类派生而来的,提供了输入方法
    • iostream类是基于istreamostream类的,因此继承了输入方法和输出方法
    • fstream类是从iostream类派生而来的,而后者基于istreamostream类,因此它继承了它们的方法
  • iostream文件中的8个流对象(4个用于窄字符流,4个用于宽字符流)
    • cin对象对应于标准输入流。在默认情况下,这个流被关联到标准输入设备(通常是键盘)。wcin对象与此类似,但处理的是wchar_t类型。
    • cout对象与标准输出流对应。在默认情况下,这个流被关联到标准输出设备(通常为显示器)。wcout对象与此类似。
    • cerr对象与标准错误流相对应,可用于显示错误消息。在默认情况下,这个流被关联到标准输出设备(通常为显示器)。这个流没有被缓冲,这意味着信息将被直接发送到屏幕,而不会等到缓冲区填满或新的换行符。wcerr对象与此类似。
    • clog对象也对应着标准错误流。在默认情况下,这个流被关联到标准输出设备(通常为显示器)。这个流被缓冲。wclog对象与此类似。

使用cout进行输出

  • write()

    • 模板原型
      basic_ostream<charT,traits>& wirte(const char_type *s,streamsize n);
      
    • write()的第一个参数提供了要显示的字符串的地址,第二个参数指出要显示多少个字符。使用cout调用write()时,将调用char具体化,因此返回类型为ostream &
    • 一个例子
      #include<bits/stdc++.h>
      using namespace std;
      int main()
      {
          const char* one="helloworld";
          const char* two="guoshen";
          int len=strlen(one);
          for(int i=1;i<=len;i++)
          {
              cout.write(one,i);
              cout<<endl;
          }
          cout.write(one,len+8);
      }
      
    • 注意,write()方法并不会在遇到空字符时自动停止打印字符。
  • 进制转换(hex(),dec(),oct())

    #include<bits/stdc++.h>
    using namespace std;
    int main()
    {
        int a=1234;
        cout<<hex<<a<<endl;//16进制
        cout<<oct<<a<<endl;//8进制
        cout<<dec<<a<<endl;//10进制
    }
    /*
    output:
    4d2
    2322
    1234
    */
    
  • int width()int width(int i)

    • 前者返回字段宽度的当前设置,后者设置字符宽度为i个空格,并返回以前的字段宽度

    • 调整字段宽度

    • 只会影响下一个项目,然后字段宽度将恢复为默认值

    • 默认是右对齐

    • 一个例子

      #include<bits/stdc++.h>
      using namespace std;
      int main()
      {
          cout<<'#';
          cout.width(12);
          cout<<12<<'#'<<24<<"#\n"<<endl;
      }
      /*
      output:
      #          12#24#
      */
      
  • fill(char a)

    • 填充未被使用的字段

    • 一直有效,直到被更改

    • 一个例子

      #include<bits/stdc++.h>
      using namespace std;
      int main()
      {
          cout<<'#';
          cout.width(12);
          cout.fill('*');
          cout<<12<<'#'<<24<<"#\n"<<endl;
      }
      /*
      output:
      #**********12#24#
      */
      
  • precision(int i)

    • 设置浮点数的显示精度为i

    • 默认精度为6位(但末尾的0将不显示)

    • 一直有效,直到被更改

    • 一个例子

      #include<bits/stdc++.h>
      using namespace std;
      int main()
      {
          double pi=acos(-1.0);
          cout<<pi<<endl;
          cout.precision(2);
          cout<<pi<<endl;
          cout.precision(10);
          cout<<pi<<endl;
      }
      /*
      output:
      3.14159
      3.1
      3.141592654
      */
      
  • setf()

    • 第一个原型
      fmtflags setf(fmtflags);
      
      • fmtflagsbitmask类型的typdef名,用于存储格式标记。
      • ios_base类中定义。
      • 参数是一个fmtflags值,指出要设置哪一位。返回值是类型为fmtflags的数字,指出所有标记以前的设置。如果打算以后恢复原始设置,则可以保存这个值。
      • 格式常量表

    常量
    os_base::boolalpha输入和输出bool值,可以为true或false
    os_base::showbase对于输出,使用C++基数前缀(0,0x)
    os_base::showpoint显示末尾的小数点
    os_base::uppercase对于16进制输出,使用大写字母,E表示法
    os_base::showpos在正数前面加+
    • 第二个原型

      fmtflags setf(fmtflags,fmtflags);
      
    • 第一个参数和以前一样,也是一个包含了所需的fmtflags值。第二个参数指出要清除第一个参数中的哪一位。

    • 调用setf()的效果可以通过unsetf()消除

    • 参数表


第二个参数第一个参数含义
ios_base::basefieldios_base::dec使用基数10
ios_base::basefieldios_base::oct使用基数8
ios_base::basefieldios_base::hex使用基数16
ios_base::floatfieldios_base::fixed使用定点计数法
ios_base::floatfieldios_base::scientific使用科学计数法
ios_base::adjustfieldios_base::left使用左对齐
ios_base::adjustfieldios_base::right使用右对齐
ios_base::adjustfieldios_base::internal符号或基数前缀左对齐,值右对齐

使用cin进行输入

  • 流状态

成员描述
eofbit如果到达文件尾,则设置为1
badbit如果流被破坏,则设置为1;例如,文件读取错误
failbit如果输入操作未能读取预期的字符或输出操作没有写入预期的字符,则设置为1
goodbit另一种表示0的方法
good()如果流可以使用(所有的位都被清除),则返回true
eof()如果eofbit被设置,则返回true
bad()如果badbit被设置,则返回true
fail()如果badbit或failbit被设置,则返回true
rdstate ()返回流状态
exceptions ()返回一个位掩码,指出哪些标记导致异常被引发
exceptions(isostate ex)设置哪些状态将导致clear()引发异常;例如,如果ex是eofbit,则如果eofbit被设置,clear()将引发异常
clear(iostate s)将流状态设置为s;s的默认值为0(goodbit);如果(restate()&exception())!=0,则引发异常basic_ios::failure
setstate(iostate s)调用clear(rdstate() | s).这将设置与s中设置的位对应的流状态位,其他流状态位保持不变
  • I/O和异常
    • 修改流状态涉及clear()setstate(),这都将会使用clear(),修改流状态后,clear()方法将当前的流状态与exceptions()返回的值进行比较。如果在返回值(exceptions())中某一位被设置,而在当前状态中对应位也被设置,则clear()将引发ios_base::failure异常。

    • exceptions()的默认设置为goodbit,也就是没有引发异常,但重载的exceptions(iostate)函数使得能够控制其行为:

      cin.exceptions(badbit)
      
    • 一个例子

      #include<bits/stdc++.h>
      using namespace std;
      int main()
      {
          cin.exceptions(ios_base::failbit);
          int x;
          int sum=0;
          try
          {
              while(cin>>x)
              {
                  sum+=x;
              }
          }
          catch(ios_base::failure &bf)
          {
              cout<<bf.what()<<endl;
          }
          cout<<sum<<endl;
      }
      /*
      input:
      10
      20
      30
      pi
      output:
      basic_ios::clear
      60
      */
      
      
  • 一些函数
    • get()getline()ignore()
      • get()会将换行符留在输入流中,接下来的输入操作首先会是换行符,而getline()不会

      • ignore()的原型为

        istream & ignore(int =1,int =EOF)
        

        该函数接受两个参数,一个是数字,指定要读取的最大字符数;另一个是字符,用作输入分界符。下面的函数调用读取并丢弃接下来的255个字符或直到到达第一个换行符

        cin.ignore(255,'\n');
        

文件的输入和输出

  • 二进制文件
    • 二进制文件比较精确

    • 要使用成员函数read()write()

    • 适用于结构体和不使用虚函数的类。

    • 一个例子

      #include<bits/stdc++.h>
      using namespace std;
      struct planet
      {
          char name[20];
          double populatition;
          double g;
      };
      const char *file="planets.dat";
      inline void eatline(){while(cin.get()!='\n')continue;}
      
      int main()
      {
          planet p1;
          cout<<fixed<<right;
          ifstream fin;
          fin.open(file,ios_base::in|ios_base::binary);
          if(fin.is_open())
          {
              while(fin.read((char*)&p1,sizeof p1))
              {
                  cout<<setw(20)<<p1.name<<": "
                      <<setprecision(0)<<setw(12)<<p1.populatition
                      <<setprecision(2)<<setw(6)<<p1.g<<endl;
              }
              fin.close();
          }
      
          //add new data
          ofstream fout(file,ios_base::out|ios_base::app|ios_base::binary);
          if(!fout.is_open())
          {
              cerr<<"Can't open"<<file<<endl;
              exit(EXIT_FAILURE);
          }
      
          cin.get(p1.name,20);
          while(p1.name[0]!='\0')
          {
              eatline();
              cin>>p1.populatition;
              cin>>p1.g;
              eatline();
              fout.write((char*)&p1,sizeof p1);
              cin.get(p1.name,20);
          }
          fout.close();
          //show data
          fin.clear();
          fin.open(file,ios_base::in|ios_base::binary);
          if(fin.is_open())
          {
              while(fin.read((char*)&p1,sizeof p1))
              {
                  cout<<setw(20)<<p1.name<<": "
                      <<setprecision(0)<<setw(12)<<p1.populatition
                      <<setprecision(2)<<setw(6)<<p1.g<<endl;
              }
              fin.close();
          }
          cout<<"Done\n";
          return 0;
      }
      /*
      输入请参照书本
      */
      
    • 随机存取

      • seekg()seekp()函数
        • seekg()的原型(seekp()与之类似)

          basic_istream<charT,traits>& seekg(streamoff,ios_base::seekdir);
          basic_istream<charT,traits>& seekg(streampos);
          

          第一个原型定位到离第二个参数指定的文件位置特定距离(单位为字节)的位置;第二个原型定位到离文件开头特定距离(单位为字节)的位置

        • 示例(假设fin是一个iftream对象)

          fin.seekg(30,ios_base::beg);//30 bytes beyond the begining
          fin.seekg(-1,ios_base::cur);//back up one byte
          fin.seekg(0,ios_base::end);//go to the end of the file
          fin.seekg(112);//go to the 113 bytes
          
      • 创建临时文件
        • tmpnam()
          • 原型

            char * tmpnam(char * pszName);
            

            创建一个临时文件名,将它放在pszName指向的C-风格字符串中

          • 常量L_tmpnam为文件名包含的最大字数,TMP_MAX为该函数在不生成重复文件名的情况下最多可调用次数

          • 一个例子

            #include<bits/stdc++.h>
            using namespace std;
            int main()
            {
                char tmp[L_tmpnam]={'\0'};
                for(int i=0;i<10;i++)
                {
                    tmpnam(tmp);
                    cout<<tmp<<endl;
                }
            }
            
            

内核格式化

  • C++库提供了sstream族,它们使用相同的接口提供程序和string对象之间的I/O。

  • 头文件sstream定义了一个从ostream类派生而来的ostringstream类。如果创建了一个ostringstream对象,则可以将信息写入其中,它将存储这些信息。

  • ostringstream类有一个名为str()的成员函数,该函数返回一个被初始化为缓冲区内容的字符串对象

  • 一个例子

    #include<bits/stdc++.h>
    using namespace std;
    int main()
    {
        ostringstream outstr;
        string tmp;
        getline(cin,tmp);
        int cap;
        cin>>cap;
        outstr<<"hello world "<<tmp<<" has a capacity of "<<cap<<endl;
        string result=outstr.str();
        cout<<result<<endl;
    }
    
    
  • istringstream类允许使用istream方法族读取istringstream对象的数据,istringstream对象可以使用string对象进行初始化

  • 一个例子

    #include<bits/stdc++.h>
    using namespace std;
    int main()
    {
        istringstream in(string("guo shen is a cool boy!"));
        string tmp;
        while(in>>tmp)
        {
            cout<<tmp<<endl;
        }
    }
    
    
  • 总之,istringstreamostringstream类使得能够使用istreamostream类的方法来管理存储在字符串中的字符数据。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值