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

文章目录

一、 总述

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

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

*名字以w开头,代表宽字符,例如,wistream读宽字符。

*使用iostream,fstream,stringstream,可以不用考虑是否是宽字符类型。

二、输出缓冲

每个输出流都管理一个缓冲区,用来保存程序读写的数据。

cout<<"Hello,World!";

文本串可能立即打印出来,也有可能被操作系统保存缓存区中,随后再打印出来。
想要立即打印出来(数据真正写到输出设备或文件)就需要刷新缓冲区。

导致缓冲刷新的原因:

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

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

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

每个流同时最多关联到一个流,但多个流可以关联到同一个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关联的文件是否成功打开且尚未关闭。
cpp 复制代码
ifstream in(ifile);  //打开指定文件。
ofstream out;  //未绑定文件
out.open(ifile)  //打开指定文件
if(out)  //检查open是否成功,open成功,我们可以使用文件了,
.......
in.close();
out.close();

3、如果目前文件流已经关联了一个文件,为了将文件流关联到另外一个文件,必须首先关闭已经关联的文件。一旦文件成功关闭,我们可以打开新的文件。

当一个fstream对象离开作用域时,与之关联的文件会自动关闭。当一个fstream对象被销毁时,close会自动被调用。

4、文件模式(file mode)

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

5、每个文件流类型都定义了一个默认的文件模式,当我们未指定文件模式时,就使用默认的模式。与ifsream关联的文件默认以in模式打开;ofstream关联的默认以out模式打开。与fstream关联的文件默认以in和out模式打开。

6,、默认情况下,当我们打开一个ofstream时,文件的内容会被丢弃。阻止一个ofstream清空给定文件内容的方法是同时指定app模式。

cpp 复制代码
ofstream app("file",ofstream::app);  //隐含为输出模式
ofstream app("file",ofstream::out|ofstream::app);  //两者等价

四、string流

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

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

2、stringstream特有的操作

sstream strm strm是一个未绑定的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

代码:

cpp 复制代码
//成员默认为公有
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);
}

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*复原

cpp 复制代码
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

2、指定整型值的进制

默认情况下是十进制。

操纵符如下:

十六进制:hex

八进制:oct

十进制:dec
这些操纵符只影响整型运算对象,浮点值的表示形式不受影响。

cpp 复制代码
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进制就可以

3、在输出中指出进制

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

cpp 复制代码
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

4、控制浮点数格式

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

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

默认情况下,

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

4.1、 指定打印精度

我们可以通过调用IO对象的precision成员或使用setprecision操纵符来改变精度。

setprecision操纵符定义在头文件iomanip中。

cpp 复制代码
//第一种方法
cout.precision(12);
double pi=3.14156;
cout<<pi<<endl;

//第二种方法
cout<<setprecision(12);
cout<<pi<<endl;
//默认情况下精度为6,想恢复,把它设置成6即可

5、输出空白

  • setw指定下一个数字或字符串值的最小空间
  • left 表示左对齐
  • right 表示右对齐
  • internal 控制负数的符号的位置。用空格填满所有中间空间
  • setfill 允许指定一个字符代替默认的空格来补白输出
cpp 复制代码
#include<iostream>
#include<iomanip>
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;
}

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

标准库还提供了一组底层操作,支持未格式化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返回,但不从流中删除它
cpp 复制代码
#include<iostream>
#include<iomanip>
using namespace std;
int main() {
	int ch;
	while (ch=cin.get())
		cout.put(ch);
	return 0;
}
cpp 复制代码
#include<iostream>
#include<iomanip>
using namespace std;
int main() {
	char ch;
	while (cin.get(ch))
		cout.put(ch);
	return 0;
}

运行结果:

输入什么,就输出什么。

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

这些操作主要用在ofstram,ifstream,ostringstream,istringstream.

pos通常是tellg或者tellp返回的值。

相关推荐
喵叔哟2 分钟前
重构代码之移动字段
java·数据库·重构
喵叔哟2 分钟前
重构代码之取消临时字段
java·前端·重构
fa_lsyk4 分钟前
maven环境搭建
java·maven
林开落L10 分钟前
前缀和算法习题篇(上)
c++·算法·leetcode
Prejudices23 分钟前
C++如何调用Python脚本
开发语言·c++·python
Daniel 大东23 分钟前
idea 解决缓存损坏问题
java·缓存·intellij-idea
单音GG25 分钟前
推荐一个基于协程的C++(lua)游戏服务器
服务器·c++·游戏·lua
wind瑞30 分钟前
IntelliJ IDEA插件开发-代码补全插件入门开发
java·ide·intellij-idea
HappyAcmen30 分钟前
IDEA部署AI代写插件
java·人工智能·intellij-idea
马剑威(威哥爱编程)35 分钟前
读写锁分离设计模式详解
java·设计模式·java-ee