• c++中的流


    streambuf类为缓冲区提供内存,并提供了用于填充缓冲区,访问缓冲区,刷新新缓冲区和管理缓冲区内存的类方法。

    ios_base类表示流的一般特征,如是否可读,是二进制还是文本流等。

    ios类基于ios_base,其中包括了一个之指向streambuf对象的的指针成员。

    缓冲区介绍

    输入:从磁盘上读取大量信息,将这些信息存储在缓冲区中,然后每次从缓冲区读取一个字节,到达缓冲区尾部,在从磁盘上读取另一块数据。

       但是键盘每次输入一个字符时可以用不缓冲区,但是用缓冲区输入可以让程序没有传给程序之前返回并改正,c++通常是用户按下回车键刷新缓冲区,

    输出:程序首先填满缓冲区,然后把整块数据给磁盘,并清空缓冲区,已备下一批输入。

       对于输出屏幕,输出换行符时刷新缓冲区(也可能是其他:当输入语句到达时,他刷新缓冲区中当前所有输出)

    刷新缓冲:用cout将字节发送给标准输出时由于ostram类对cout对象输出进行缓冲,输出并不会直接发送到目标地址,而是在缓冲区中,直到缓冲区填满,然后flush缓冲区,把内容发送出去并且清空缓冲,缓冲区通常为512byte或其整数倍。

      对于屏幕来说,程序不必等到缓冲区填满,1.将换行符发送到缓冲区时刷新缓冲区;2.输入即将发生时刷新缓冲区。

      由于程序运行时并不总是知道外部输入的进度,很难控制是不是全部清除输入缓冲区的内容。通常我们有可能只是希望放弃输入缓冲区中的一部分,而不是全部。比如清除掉当前行、或者清除掉行尾的换行符等等。但要是缓冲区中已经有了下一行的内容,这部分可能是我们想保留的。这个时候最好不要用sync()。可以考虑用ignore函数代替

    cin.ignore(numeric_limits<std::streamsize>::max(),'/n');//清除当前行
    cin.ignore(numeric_limits<std::streamsize>::max());     //清除cin里所有内容

    numeric_limits<std::streamsize>::max()不过是climits头文件定义的流使用的最大值,你也可以用一个足够大的整数代替它。使用ignore显然能比sync()更精确控制缓冲区

    cin.ignore(1024,' '),通常把第一个参数设置得足够大,这样实际上总是只有第二个参数' '起作用,所以这一句就是把回车(包括回车)之前的所以字符从输入缓冲(流)中清除出去。

    flush(cout);
    cout<<"hello word"<<flush;
    cout<<"hello word"<<endl;//刷新缓冲区并插入换行符 

    以上三种方式均可以刷新缓冲区

    但cout<<' ';只是输出换行符,不刷新缓冲区; 只代表换行的转义字符; 是C中间的格式输出换行,C++保留了下来;输出' '是实际输出了的'10',往输出流里添加了信息,所有的字符都是'xx'的形式,换行符也是,你用其它任何字符输出一下,前面都会有四个'*'填充的

    程序员常常在调试时添加打印语句。这类语句应该保证‘一直’刷新流。否则,如果程序崩溃,输出可能还停留在缓冲区中,从而导致关于程序崩溃位置的错误推断

    缓冲区的操作https://liam.page/2017/12/31/buffer-of-stream-in-Cpp/   https://izualzhy.cn/stream-buffer

    #include <iostream> 
    #include <sstream>
    #include <cstdio>
    using namespace std;
    
    int main()
    {
        stringstream ss;
        streambuf *buf=cout.rdbuf();
        //使用了新的缓冲区后,字符串不会输出到屏幕,而是由stringstream管理
        cout.rdbuf(ss.rdbuf());
        cout<<"hello word"<<endl;
        
        printf("%s",ss.str().c_str());
        
        cout.rdbuf(buf);
        cout<<"hello word"<<endl;
        return 0;
    }

    基于控制台

    继承关系

    c++将输出看做字节流,将数值类型转换为文本形式表示的字符流(将数据内部表示(二进制形式)转换为字符字节组成的输出流)

    cout:对于void*类型,打印其地址数值(一端关联显示器另一端关联程序

    cin:从非空白字符开始,到与目标类型不匹配的第一个字符之间的全部内容(一端关联键盘另一端关联程序

    cerr:关联输出设备(通常为显示器)没有缓冲区,信息直接输出到屏幕,不会等到新的换行或缓冲区满

    clog:关联输出设备(通常为显示器)有缓冲区

    ostream:ostream &<<使用该操作符返回一个指向该对象的引用,插入操作符的返回值是调用该操作符的对象

            int a=0,sum=0;
        while(cin>>a)
            sum+=a;
        //输入1 2 3 4 5 6c 60     

    由于输入缓冲,在用户键入回车之前不会发送给程序,但是循环在了对字符c出停止了处理,导致cin>>a返回alse,终止循环

    状态流

      cin或cout对象包含一个描述状态流的数据成员(继承于ios_base)被定义为iostate,是bitmask类型,由eofbit,badbit,failbit,每一位可以是1(设置)0(清除)

    clear:将状态设置为他的参数,默认0清楚全部状态;clear(eofbit),eofbit被设置,其他清除

    setstate:setstate(eofbit)只设置eofbit,不影响其他位

    get()与getline():get将换行符留在流中,getline抽取并丢弃输入流中的换行符

    char tem[60];
    while(cin.get(tem,60))//空行终止 
    {
        //...
    }
    
    //空行不终止,因为空行不导致getline设置failbit,getline抽取换行符并丢弃 
    while(cin.getline(tem,60)) 
    {
        //...
    }
    //空行终止 
    while(cin.getline(tem,60)&&tem[0]!='') 
    {
        //...
    }

    I/O异常

      exceps()返回一个为字段,包含三位:eofbit,failbit,badbit。修改流状态后,clear()函数将当前流状态与exceps()的返回值比较,如果返回值中某一位被设置,当前流转态位对应位也被设置,则clear()引发ios_base::failure异常,exceptions()返回good不会引发异常,ios_base::failure从exception类派生,因此包含一个what()函数。

    #include <iostream> 
    #include <exception>
    using namespace std;
    
    int main()
    {
        cin.exceptions(ios_base::failbit);
        
        int a=0,sum=0;
        try
        {    
            while(cin>>a)
                sum+=a;
        }
        catch(ios_base::failure &bf)
        {
            cout<<bf.what()<<endl;
        }
        
        cout<<"last input:"<<a<<endl;
        cout<<"sum:"<<sum<<endl;
        return 0;
    }
    #include <iostream>
    #include <exception>
    #include <fstream>
    using namespace std;
    
    //filebuf in;
    //istream i(&in);
    int main()
    {
        int a=0,sum=0;
        while(cin>>a)//只有状态流良好(所有为都被清楚)的情况下,while或if才返回true 
            sum+=a;
    
        cout<<"last input:"<<a<<endl;
        cout<<"sum:"<<sum<<endl;
        
        if(cin.fail()&&!cin.eof())
        {
            cin.clear();
            while(!isspace(cin.get()))//get提供不跳过空白字符读的功能 
                continue;
        }
        else
        {
            cout<<" i cannot go on"<<endl;
            exit(1);
        }
        cout<<"now input a new number:";
        cin>>a;
        
        return 0;
    }

    cin.get(char &):到达文件末尾(真正的文件末尾,或键盘仿真文件末尾---win下ctrl+z---UNIX下ctrl+d,都不会给参数赋值,返回eof

    cin.get():返回int类型的值,后不能跟抽取操作符,如:cin.get().get()>>c;

    基于文件

    继承关系

    程序写入文件

    1. 创建一个ofstream对象管理输出流
    2. 将对象与特定的文件关联
    3. 用cout的方式使用该对象
    4. 使用colse()显示关闭文件的链接;(对象过期时(程序中止))文件的链接会自动关闭
      #include <iostream>
      #include <fstream>
      using namespace std;
      
      int main()
      {
          ofstream of;
          of.open("1.txt");
          //ofstream of("1.txt");//也可以用构造函数 
          
          of<<"ds";
          of.close();//关闭文件将刷新缓冲区,确保文件被更新 
          return 0;
      }

    读取文件

    1. 创建一个ifstream对象管理输出流
    2. 将对象与特定的文件关联
    3. 用cin的方式使用该对象
    4. 使用colse()显示关闭文件的链接;(对象过期时(程序中止))文件的链接会自动关闭
      #include <iostream>
      #include <fstream>
      using namespace std;
      
      int main()
      {
          ifstream fin;
          fin.open("1.txt");
          //ifstream fin("1.txt");//也可以用构造函数,可以用is_open()检查是否打开成功,若成功流状态为0
          
          string s;
          fin>>s;
          cout<<s<<endl;
          
          fin.close();//只是断开文件的链接,对象与他的缓冲区仍然存在 
          return 0;
      }

    文件流作为类成员时,其初始化只能是初始化列表方式,即构造对象时文件,不能在构造函数体中进行操作,否则文件打开失败。

    文本文件与二进制文件

      文本文件:

        所有内容都储存为文本,如:以文本格式存储123456,将存储6个字符,计算机内部将浮点数转为字符格式,这是<<插入操作符的工作;写文本文件时,linux,UNIX。dos c++自动将换行符转为回车和换行;读文本文件时,将本地的换行符转为c++格式;macintosh c++将换行转为回车。

      二进制文件:

        计算机不存储字符,而存储64位double;字符的二进制和文本表示一样(字符的ASCII二进制表示);较为精确,二进制保存数据更快,不需要转换,占用空间小,可大量存储;但二进制对于换行符,有歧义。二进制与文本文件的末未检测方式也不同。

      二进制和文本模式的区别:
      在windows系统中,文本模式下,文件以" "代表换行。若以文本模式打开文件,并用fputs等函数写入换行符" "时,函数会自动在" "前面加上" "。即实际写入文件的是" " 。
      在类Unix/Linux系统中文本模式下,文件以" "代表换行。所以Linux系统中在文本模式和二进制模式下并无区别

    #include <iostream>
    #include <fstream>
    using namespace std;
    
    struct Stu
    {
        int age;
        double weight;    
    }stu;
    
    int main()
    {
        ofstream of;
        of.open("1.txt"); 
        
        //到达stu的结构地址,并且将6个字节复制到与of相关的文件中,用write函数可以以二进制形式存储数据
        of.write((char *)&stu,sizeof(stu)); 
        of.close();//关闭文件将刷新缓冲区,确保文件被更新 
        
        //将文件中的sizeof(stu)个字节复制到结构体中 
        ifstream fin("1.txt");
        fin.read((char *)&stu,sizeof(stu));
        return 0;
    }

    基于字符串的I/O

    继承关系

    #include <iostream>
    #include <sstream>
    using namespace std;
    
    int main()
    {
        ostringstream os;
        string s("123");
        os<<s;
          cout<<os.str()<<endl;
          
          ostringstream _os;
          _os<<os.str();
          cout<<_os.str()<<endl;//让_os从os中提取数据,str()成员函数的使用可以让istringstream对象返回一个string字符串
              
        return 0;
    }

     清空stringstream对象中的内容

        vector<string> s(v.size(),"");//确定字符串数组的大小 
        stringstream ss;
        for(int i=0;i<v.size();++i)
        {
            ss<<v[i];
            s[i]=ss.str();
            ss.str("");    //清空stringstream对象中的内容,clear()只是清空了流的状态    
        }
  • 相关阅读:
    redis的初认识
    Java中自己定义缓存方式
    Ehcache整合spring
    巴菲特
    EHcache经典配置
    (1)-使用json所要用到的jar包下载
    java和json互转
    TypeToken 是google提供的一个解析Json数据的类库中一个类
    深刻理解Java编程的7个例子
    Java实现几种常见排序方法
  • 原文地址:https://www.cnblogs.com/tianzeng/p/9038810.html
Copyright © 2020-2023  润新知