• Linux系统编程-C++ I/O库


    一、 总述

    C++使用标准库类来处理面向流的输入和输出:

    • iostream处理控制台IO。
    • fstream处理命名文件IO。
    • stringstream完成内存string的IO。
    头文件类型
    iostreamistream,wistream 从流读取数据。ostream,wostream 向流写入数据。iostream,wiostream 读写流。
    fstreamifstream,wifstream 从文件读取数据。 ofstream,wofstream 向文件写入数据。fstream,wfstream 读写文件。
    sstreamistringstream,wistringstream 从string读取数据。ostringstream,wostringstream 向string写入数据。stringstream,wstringstream 读写string。

    *名字以w开头,代表宽字符,例如,wistream读宽字符。
    *使用iostream,fstream,stringstream,可以不用考虑是否是宽字符类型。

    二、输出缓冲

    每个输出流都管理一个缓冲区,用来保存程序读写的数据。
    cout<<“Hello,World!”;
    文本串可能立即打印出来,也有可能被操作系统保存缓存区中,随后再打印出来。
    想要立即打印出来(数据真正写到输出设备或文件)就需要刷新缓冲区。
    导致缓冲刷新的原因:

    1. 程序正常结束,作为main函数的return操作的一部分,刷新缓冲区。
    2. 缓冲区满时,刷新缓冲区。
    3. 我们可以使用操作符如endl,来显示的刷新缓冲区。
      操作符flush,刷新缓冲区,但不输出任何额外的字符;ends向缓冲区插入一个空字符,然后刷新缓冲区。
      例:
    cout<<"Hi!"<<endl;  //输出Hi!和一个换行,然后刷新缓冲区
    cout<<"hi!"<<flush; //输出hi,然后刷新缓冲区
    cout<<"hi!"<<ends; //输出hi和一个空字符,然后刷新缓冲区
    
    • 1
    • 2
    • 3
    1. 每个输出操作后,可以使用操作符unitbuf设置流的内部状态,来清空缓冲区。默认情况下,对cerr是设置unitbuf的,因此写到cerr的内容,都是立即刷新的。
      如果想每次输出操作后都刷新缓冲区,可以使用unitbuf操纵符。它告诉流接下来的每次写操作之后都进行一次flush操作。
      nounitbuf操作符重置流,使其恢复使用正常的系统管理的缓冲区刷新机制。
    cout<<unitbuf;  //之后所有输出操作都会立即刷新缓冲区。
    .........
    cout<<nounitbuf;  //回到正常的缓冲方式。
    
    • 1
    • 2
    • 3

    如果程序崩溃,输出缓冲区不会被刷新。

    1. 一个输出流可能被关联到另一个流。默认情况下,cin和cerr都关联到cout,当读cin或写cerr都会导致cout的缓冲区被刷新。
      tie有2个重载的版本。一个版本不带参数,返回指向输出流的指针。第二个版本接受一个指向ostream的指针,将自己关联到此ostream,即x.tie(&o)将流x关联到输出流o。
    cin.tie(&cout)//cin关联到cout
    cin.tie(&cerr);   //cin关联到cerr,读取cin时会刷新cerr
    
    • 1
    • 2

    每个流同时最多关联到一个流,但多个流可以关联到同一个ostream。

    三、文件输入输出

    1、可以用IO运算符(<<, >>)来读写文件,可以用getline从一个ifstream读取数据。
    2、 fstream特有的操作。

    fstream fstrm创建一个未绑定的文件流。
    fstream fstrm(s)创建一个fstream,并打开一个名字为s的文件。s可以是string类型或者指向c风格字符串的指针
    fsream fstrm(s,mode)与前一个构造函数类似,但按照指定mode打开文件
    fstrm.open(s)打开名为s的文件,并将文件与fstrm绑定。等价于fstream fstrm(s)
    fstrm.close()关闭与fstrm绑定的文件。返回void。
    fstrm.is_open()返回一个bool值,指出与fstrm关联的文件是否成功打开且尚未关闭。
    ifstream in(ifile);  //打开指定文件。
    ofstream out;  //未绑定文件
    out.open(ifile)  //打开指定文件
    if(out)  //检查open是否成功,open成功,我们可以使用文件了,
    .......
    in.close();
    out.close();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    3、如果目前文件流已经关联了一个文件,为了将文件流关联到另外一个文件,必须首先关闭已经关联的文件。一旦文件成功关闭,我们可以打开新的文件。
    当一个fstream对象离开作用域时,与之关联的文件会自动关闭。当一个fstream对象被销毁时,close会自动被调用。
    4、文件模式(file mode)

    fstream fstrm(s,mode);
    
    • 1
    in以读方式打开
    out以写方式打开
    app每次读写都定位到文件末尾
    ate打开文件后立即定位到文件末尾
    binary以二进制方式进行IO
    trunc截断文件

    5、每个文件流类型都定义了一个默认的文件模式,当我们未指定文件模式时,就使用默认的模式。与ifsream关联的文件默认以in模式打开;ofstream关联的默认以out模式打开。与fstream关联的文件默认以in和out模式打开。
    6,、默认情况下,当我们打开一个ofstream时,文件的内容会被丢弃。阻止一个ofstream清空给定文件内容的方法是同时指定app模式。

    ofstream app("file",ofstream::app);  //隐含为输出模式
    ofstream app("file",ofstream::out|ofstream::app);  //两者等价
    
    
    • 1
    • 2
    • 3

    四、string流

    1、sstream头文件提供了对string的操作。

    istringstream从string读取数据
    ostringstream向string写入数据
    stringstream既可从string读数据也可向string写数据

    2、stringstream特有的操作

    sstream strmstrm是一个未绑定的stringstream对象
    sstream strm(s)strm是一个sstream对象,保存string s 的一个拷贝。
    strm.str()返回strm所保存的string的拷贝
    strm.str(s)将string s拷贝到strm中,返回void

    3、当我们的某些工作是对整行文本进行处理,而其他工作是处理行内的单个单词时,通常可以使用istringstream。
    例:
    我们的输入文件看起来可能是这样的:

    morgan 2015552368 8625550123
    drew 9735550130
    lee 6095550132 2015550175 800555000

    代码:

    //成员默认为公有
    struct PersonInfo{
      string name;
      vector<string> phones;
    };
    
    string line,word;     //分别保存来自输入的一行和单词
    vector<PersonInfo> people;     //保存来自输入的所有记录
    	while(getline(cin,line)){
    		PersonInfo info;
    		istringstream record(line);     //将记录绑定到刚读入的行
    		record>>info.name;             //读取名字
    		while(record>>word){          //读取电话号码
    			info.phones.push_back(word);
    			}
    	people.push_back(info);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    4、当我们逐步构造输出,希望最后一起打印时,ostringstream是很有用的。
    我们使用标准的输出运算符(<<)向这些对象(类型为 ostringstream)写入数据,但这些“写入”操作实际转化为string操作,分别向这些对象中的string对象添加字符。

    五、输入输出格式

    总述

    标准库定义了一组操纵符来修改流的格式状态。大多数改变格式状态的操纵符都是设置/复原成对的。当操纵符改变流的格式状态时,通常改变后的状态对所有后续IO都生效。

    boolalpha将true和false输出为字符串
    *noboolalpha将true和false输出为1,0
    showbase生成显示进制的前缀
    *noshowbase不生成表示进制的前缀
    showpoint对浮点数总显示小数点
    *noshowbase只有当浮点值包含小数部分时才显示小数点
    showpos对非负数显示+
    *noshowpos对非负数不显示+
    uppercase十六进制打印0X,科学计数法打印E
    *nouppercase十六进制打印0x,科学计数法打印e
    *dec整型值显示为十进制
    hex整型值显示为十六进制
    oct整型值显示为八进制
    left在值的右侧填充字符
    right在值的左侧填充字符
    internal在符号和值之间填充字符
    fixed浮点值显示为定点十进制
    scientific浮点值显示科学计数法
    hexfloat浮点值显示十六进制
    defaultfloat重置浮点数格式为十进制
    umitbuf每次输出操作后都刷新缓冲区
    *nounitbuf恢复正常刷新缓冲区方式
    *skipws输入运算符跳过空白符
    noskipws输入运算符不跳过空白符
    flush刷新打印缓冲出
    ends插入空字符,然后刷新打印缓冲区
    endl插入换行,然后刷新打印缓冲区
    *表示默认流状态

    1、控制布尔值的格式

    boolalpha操纵符
    noboolalpha*复原

    cout<<true<<" "<<false<<endl;  //输出1 0
    cout<<boolalpha<<true<<" "<<false<<endl; // 输出true false
    cout<<true<<" "<<false<<endl;  //  因为改变了输出格式,还没有复原,所有输出 true false
    cout<<noboolalpha;    //复原
    cout<<true<<" "<<false<<endl;  //因为恢复了默认格式,所以输出 1,0
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2、指定整型值的进制

    默认情况下是十进制。
    操纵符如下:
    十六进制:hex
    八进制:oct
    十进制:dec
    这些操纵符只影响整型运算对象,浮点值的表示形式不受影响。

    cout<<20<<" "<<1024<<endl;    //输出 20 1024
    cout<<hex<<20<<" "<<1024<<endl;  //14 400
    cout<<oct<<20<<" "<<1024<<endl;  //24 2000
    cout<<dec<<20<<" "<<1024<<endl;   //20 1024
    
    //指定进制想要变回默认10进制,就指定它类型为10进制就可以
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3、在输出中指出进制

    使用showbase操纵符
    noshowbase恢复默认状态。

    cout<<showbase;  //打印整型时显示进制
    cout<<20<<" "<<1024<<endl;    //输出 20 1024
    cout<<hex<<20<<" "<<1024<<endl;  //0x14 0x400
    cout<<oct<<20<<" "<<1024<<endl;  //024 02000
    cout<<dec<<20<<" "<<1024<<endl;   //20 1024
    cout<<noshowbase;  // 恢复流状态,不再显示整型值的进制
    
    //默认情况下十六进制是小写打印,使用uppercase操纵符,可以变成大写。nouppercase ,变回小写
    cout<<uppercase<<showbase<<hex<<20<<" "<<1024<<endl;  //0X14 0X400
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    4、控制浮点数格式

    可以控制浮点数输出三种格式

    • 以多高精度打印浮点数。
    • 数值是打印为十六进制、定点十进制、还是科学计数法形式。
    • 对于没有小数部分的浮点值是否打印小数点。

    默认情况下,

    • 浮点数按6位数字精度打印。
    • 如果浮点值没有小数部分,则不打印小数点。
    • 标准库会选择一种可读性更好的格式,来输出。

    4.1、 指定打印精度

    我们可以通过调用IO对象的precision成员或使用setprecision操纵符来改变精度。
    setprecision操纵符定义在头文件iomanip中。

    //第一种方法
    cout.precision(12);
    double pi=3.14156;
    cout<<pi<<endl;
    
    //第二种方法
    cout<<setprecision(12);
    cout<<pi<<endl;
    //默认情况下精度为6,想恢复,把它设置成6即可
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    5、输出空白

    • setw指定下一个数字或字符串值的最小空间
    • left 表示左对齐
    • right 表示右对齐
    • internal 控制负数的符号的位置。用空格填满所有中间空间
    • setfill 允许指定一个字符代替默认的空格来补白输出
    #include
    #include
    using namespace std;
    int main() {
    	int i = -16;
    	double d = 3.14159;
    	cout << setw(12) << i <<" next" << endl;
    	cout << setw(12) << d <<" next" << endl;
    	cout << left<< setw(12) << i << " next" << endl
    	 << setw(12) << d << " next" << endl;
    	cout << right << setw(12) << i << " next" << endl
    	 << setw(12) << d << " next" << endl;
    	cout << internal << setw(12) << i << " next" << endl
    		<< setw(12) << d << " next" << endl;
    	cout << setfill('#') << setw(12) << i << " next" << endl
    		<< setw(12) << d << " next" << endl<<setfill(' ');
    		return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述

    六、未格式化的输入输出操作

    标准库还提供了一组底层操作,支持未格式化IO,这些操作允许我们将一个流当做一个无解释的字节序列来处理

    is.get(ch)读取一个字节存入字符ch,返回is
    os.put(ch)将字符输出到os,返回os
    is.get()将is的下一个字节作为int返回
    is.putback()将字符ch放回is,返回is
    is.unget()将is向后移动一个字符,返回is
    is.peek()将下一个字节作为int返回,但不从流中删除它
    #include
    #include
    using namespace std;
    int main() {
    	int ch;
    	while (ch=cin.get())
    		cout.put(ch);
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    #include
    #include
    using namespace std;
    int main() {
    	char ch;
    	while (cin.get(ch))
    		cout.put(ch);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    运行结果:
    输入什么,就输出什么。

    tellg()返回输入流中的标记的当前位置
    tellp()返回输出流中的标记的当前位置
    seekg(pos)重定位到给定地址
    seekp(pos)重定位到给定地址
    seekp(off,from)将标记定位到from之前或之后off个字符
    seekg(off,from)将标记定位到from之前或之后off个字符

    这些操作主要用在ofstram,ifstream,ostringstream,istringstream.
    pos通常是tellg或者tellp返回的值。

  • 相关阅读:
    ModuleNotFoundError: No module named ‘Crypto.Cipher‘或‘Crypto 的终极解决方案
    升级打怪课堂的题库更新了!
    网络代码理解
    IDEA新建一个spark项目
    设计模式 - 代理模式
    SNI代理与DNS解析相结合
    论文阅读 3 | Few-shot Domain Adaptation by Causal Mechanism Transfer
    Linux vi/vim
    数商云经销商系统促销功能解析,灵活定义促销方案助力家居建材企业抢占市场
    java计算机毕业设计共享汽车管理系统源码+mysql数据库+系统+LW文档+部署
  • 原文地址:https://blog.csdn.net/ccb1372098/article/details/132803578