1.基本IO库文件
C++为处理不同类型IO操作,分别在iostream中定义了用于读写流的基本类型,fstream中定义了读写文件的类型,sstream中定义了读写string对象的类型。如下所示:
- iostream: istream, wistream 从流读取数据
ostream, wostream 向流写入数据
iostream, wiostream 读写流 - fstream: ifstream, wifstream 从文件读取数据
ofstream, wofstream 向文件写入数据
fstream, wfstream 读写文件 - sstream: istringstream, wistringstream 从string读取数据
ostringstream, wostringstream 向string写入数据
stringstream, wstringstream 读写string - streambuf: 流缓冲区基类,包含文件缓冲类filebuf和字符串缓冲类stringbuf
常用的类型有:
- istream:输入流类型,提供输入操作
- ostream:输出流类型,提供输出操作
- cin:一个istream对象,从标准输入读取数据
- cout:一个ostream对象,向标准输出写入数据
- cerr:一个ostream对象,用于输出错误消息写入到标准错误
- '>>运算符:从一个istream对象读取输入数据
- <<运算符:向一个ostream对象写入输出数据
- getline:从一个给定的istream读取一行数据,存入string对象中
对于操作符endl,我们知道它的作用是换行并刷新缓冲区,类似的操作符还有flush和ends,它们的作用如下:
cout<<"hello"<<endl; //输出hello并换行,然后刷新缓冲区
cout<<"hello"<<flush; //输出hello,然后刷新缓冲区
cout<<"hello"<<ends; //输出hello和一个空字符,然后刷新缓冲区
注意1: IO对象不能进行拷贝或赋值
ofstream o1, o2;
o1 = o2; //错误,不能对流对象赋值
ofstream print(ofstream); //错误,不能初始化ofstream参数
o1 = print(o1); //错误,不能拷贝流对象
1.1 操作符
标准库定义了一组操作符来修改流的格式状态,一个操作符是一个函数或对象,能用做输入或输出运算符的运算对象。操作符用于两大类输出控制:控制数值输出形式和控制补白的数量和位置。
注意2: 当操作符改变流的格式状态时,通常改变后的状态对所有后续IO都有效
- boolalpha操作符控制布尔值格式
cout << "default bool values: "<< true <<" " << false
<< "\nalpha bool values: "<< boolalpha << true <<" "<< false << endl;
运行得到结果如下:
default bool values: 1 0
alpha bool values: true false
- hex、oct、dec和showbase操作符控制整型值进制显示和输出
cout << showbase; //显示进制
cout << "default: "<< 20 <<" "<< 1024 <<endl; //默认十进制
cout << "octal: "<< oct << 20 <<" "<< 1024 <<endl; //八进制
cout << "hex: " << hex << 20 <<" "<< 1024 <<endl; //十六进制
cout << "decimal: " << dec << 20 <<" "<< 1024 <<endl;//十进制
cout << noshowbase; //恢复流状态
运行得到结果如下:
default: 20 1024
octal: 024 02000
hex: 0x14 0x400
decimal: 20 1024
注意3: 操作符hex、oct、dec只影响整型运算对象,不影响浮点值表示
- precision成员、setprecision操作符指定打印精度
cout.precision(6); //打印精度6位
cout << "precision: " << cout.precision() << ",value: " << sqrt(3.0) <<endl;
cout<<setprecision(3); //打印精度3位
cout << "precision: " << cout.precision() << ",value: " << sqrt(3.0) <<endl;
运行得到结果如下:
precision: 6,value: 1.73205
precision: 3,value: 1.73
- 为更好地控制数据格式,标准库提供以下操作符
- setw:指定下一个数字或字符串值的最小空间
- left:左对齐输出
- right:右对齐输出,默认格式
- internal:控制负数的符号位置,左对齐符号右对齐值,空格填满中间
- setfill:允许指定一个字符代替默认空格输出
int a = -100;
cout << "a: " << setw(10) << a <<endl;
cout << left << "a: " << setw(10) << a <<endl;
cout << right << "a: " << setw(10) << a <<endl;
cout << internal << "a: " << setw(10) << a <<endl;
cout << setfill('#') << "a: " << setw(10) << a <<endl;
运行得到结果如下:
a: -100
a: -100
a: -100
a: - 100
a: -######100
2.文件输入输出操作
标准库除了提供格式化的IO操作之外,还提供了一组底层操作来支持未格式化的IO操作,如下:
-
is.get(ch): 从istream is读取一下个字节存入字符ch并返回is
-
os.put(ch): 将字符ch输出到ostream os并返回os
-
is.get(): 将is的下一个字符作为int返回
-
is.putback(ch): 将字符ch放回is并返回is
-
is.unget(): 将is向后移动一个字节并返回is
-
is.peek(): 将下一个字节作为int返回,但不从流中删除它
-
is.get(sink,size,delim): 从is中读取最多size个字节,保存到sink为起始地址的字符数组。读取时直到遇到delim字符或读取size个字节或到文件尾停止。遇到delim不读取
-
is.getline(sink,size,delim): 与get类似,但会读取delim并丢弃
-
is.read(sink,size): 读取最多size个字节存入字符数组sink中并返回is
-
is.gcount(): 返回上一个未格式化读取操作从is读取的字节数
-
os.write(source,size): 将字符数组source中的size个字节写入os并返回os
对一个文件进行读和写操作可使用文件流对象进行,文件流对象与文件关联,每个文件流都定义了一个open的成员函数进行文件的读或写。每个流都有一个关联的文件模式,用来指出如何使用文件。
2.1 文件模式有以下几种:
- in :以读方式打开,只可对ifstream或fstream对象设定
- out :以写方式打开,只可对ofstream或fstream对象设定
- app :每次写操作前都定位到文件末尾,只有trunc没设定就可设定app模式
- ate :打开文件后立即定位到文件末尾,可用于任何类型文件流对象
- trunc :截断文件,只有当out也设定时才可设定trunc模式
- binary :以二进制方式进行,可用于任何类型文件流对象
基本使用如下:
ofstream out1(filename,ofstream::out); //以输出模式打开文件并截断文件
ofstream out2(filename,ofstream::out | ofstream::trunc); //以输出模式打开文件并截断文件
ofstream app1(filename,ofstream::app); //显式指定app模式,保留文件内容
ofstream app2(filename,ofstream::out | ofstream::app); //显式指定app模式,保留文件内容
ofstream out; //未指定打开模式
out.open(file); //隐含输出和截断
out.close();
out.open(file1,ofstream::app); //输出和追加
out.close();
注意4:默认情况以out模式打开文件会丢失现有数据。保留被ofstream打开的文件中数据的方式是指定app模式或in模式
2.2 输入输出运算符重载
输入运算符的第一个形参是运算符将要读取的流的引用,第二个形参是将要读入的对象的引用。
输出运算符的第一个形参是一个非常量ostream对象引用,第二个形参一般是一个常量的引用。
//输出运算符重载示例
friend std::ostream &operator<<(std::ostream &os, const Edge &edge) {
os << edge.a << " - " << edge.b << ": " << edge.c;
return os;
}
//输入运算符重载示例
friend std::ostream &operator>>(std::istream &is, const Edge &edge) {
is >> edge.a >> edge.b >> edge.c;
if(is)
......
return isl
}
注意5: 输入运算符需要检查是否成功,输出运算符不需要
2.3 示例代码
ifstream file(filename); //创建文件流对象打开给定文件,open会自动调用
assert(file.is_open()); //需要判断文件是否打开成功
file.close(); //file对象使用完成之后可手动调用close关闭
// 1.获取键盘输入
string line; //string是C++提供的字符串类
cout<<"input a line with enter: ";
getline(cin, line, '\n');
cout << line << endl;
// 2.按行读取文件内容
ifstream file(filename); //将filename读进file中
string line; //按行读取
assert(file.is_open()); //判断文件是否成功打开
assert(getline(file,line)); //使用getline()读取file中的第一行放进line,再判断读取成功
stringstream ss(line); //line放进stringstream中。对一行文本中内容进行操作时,通常可使用stringstream进行操作
for(int i=0;i<N;++i){ //循环读取
assert(getline(file, line));
stringstream ss(line);
int a, b;
ss >> a >> b; //取出ss中的两个数据到x和y
}
// 3.数值转字符串输出
ostringstream ss;
ss << 1024; //向stringstream中写数据
ss << " c++ ostringstream"; //向stringstream中写数据
cout << ss.str() <<endl; //str()创建一个临时string对象将流生成字符串
// 4.向文件写入用户输入数据
ofstream os;
string line;
os.open("file.dat", ofstream::out | ofstream::app); //写模式打开文件,保留文件并追加输出
cout<<"input a line with enter: ";
getline(cin, line, '\n'); //获取输入一行数据
os << line << endl; //放入ofstream
References:
- 《Primer c++》第五版