目录
- 简介
- ios类库
- streambuf类库
- 标准I/O流——iostream
- 预定义流对象
- cin
- cout
- 标准输出流
- put()
- write()
- 标准输入流
- get()
- getline()
- read()
- ignore()
- gcount()
- peek()
- 文件流
- 文件流对象的创建
- 文件打开和关闭
- 文本文件的读写
- 二进制文件的读写
- 文件随机读写
- 字符串流
简介
I/O流类库是C++标准库的重要组成部分,它主要包括ios类库和streambuf类库。其中,ios类库提供流的高级I/O操作,streambuf类库主要负责缓冲区的处理。
ios类库

抽象基类ios被istream、ostream类继承,其中istream类是输入流类,ostream类是输出流类,它们定义了输入流和输出流的基本特性。
- ifstream类:文件输入流类,支持文件的读操作。
- ofstream类:文件输出流类,支持文件的写操作。
- istringstream类:字符串输入流类,支持字符串的输入操作。
- ostringstream类:字符串输出流类,支持字符串的输出操作。
- iostream类
- fstream类:文件输入/输出流类,支持文件的读写操作。
- stringstream类:字符串输入/输出流类,支持字符串的输入和输出操作。
streambuf类库

streambuf类是一个抽象类,提供了缓冲区操作接口,如设置缓冲区、从缓冲区提取字节、向缓冲区插入字节等。
streambuf类派生了3个类,分别是stdiobuf类、filebuf类、stringstreambuf类。其中,stdiobuf类用于标准I/O缓冲区管理,filebuf类用于文件缓冲区管理,stringstreambuf类用于内存缓冲区管理。
标准I/O流——iostream
标准输入流和标准输出流的一系列操作方法都是由istream和ostream两个类提供的,这两个类继承自抽象基类ios,它们预定义了标准输入流对象和标准输出流对象,并且提供了多种输入/输出方法。
预定义流对象
C++提供了四个预定义流对象,包括cin、cout、cerr和clog。
预定义流对象 | 说明 | 类型 |
cin | 处理标准输入(键盘输入),有缓冲 | istream |
cout | 处理标准输出(屏幕输出),有缓冲 | ostream |
cerr | 处理标准错误信息,无缓冲 | ostream |
clog | 处理标准错误信息,有缓冲 | ostream |
cin
cin与运算符“>>”结合使用,用于读入用户输入,以空白(包括空格、Enter、Tab)为分隔符。
cout
cout与运算符“<<”结合使用,用于向控制台输出信息。在用cout输出变量值时,“<<”运算符会根据变量的数据类型自动匹配并正确输出。
- 指定输出数字格式
通过C++标准库提供的标志位和操作符控制格式,这些操作符位于iomanip头文件。
#include <iostream>
#include <iomanip>
using namespace std;
int a = 10;
cout << "输出十进制" << a << endl; //10
cout << "输出八进制" << oct << a << endl; //12
cout << "输出十六进制" << hex << a << endl;//a- 指定数据精度
使用setprecision()函数可以设置浮点类型输出所需精度数据。
#include <iostream>
#include <iomanip>
double pi = 3.141592653589;
cout << setprecision(5) << pi << endl; //3.1416- 指定域宽、对齐方式、填充方式的数据
C++提供了setw()函数用于指定域宽,setiosflags()函数用于设置对齐方式,setfill()函数用于设置填充方式。
#include <iostream>
#include <iomanip>
double pi = 3.141592653589;
cout << setprecision(5) <<setfill('*')<<setw(10)<<setiosflags(ios::left)<< pi << endl;//3.1416****标准输出流
ostream类除了预定义流对象cout,还提供了成员函数用于输出数据,比较常用的两个成员函数为put()函数和write()函数。
put()
put()函数用于输出单个字符,函数返回值为ostream类对象引用,所以可以连续调用。
cout.put('a').put('\n').put('d');write()
write()函数用于输出一个字符串,第一个参数str表示字符串;第二个参数count表示输出的字符个数,其同样可以连续调用。
cout.write("hello",5).write(",world",6);//hello,world
//不满5个会用空格填满标准输入流
istream类预定义了输入流对象cin,并且重载了“>>”运算符,输入流对象与“>>”运算符结合使用,可以输入各种类型的数据。此外,istream类还提供了成员函数用于输入数据,如get()函数、getline()函数、read()函数等
get()
istream类重载了多个get()函数。常用的重载形式有以下三种。
int get(); //是从输入流读取一个字符,返回该字符的ASCII码值
istream& get(char &ch);//从输入流读取一个字符存储到字符ch中
istream& get(char *dst,streamsize count,char delimiter);//delimiter默认'\0',表示结束符,count表示读取字符串长度char ch;
cout << "请输入一个字符串:"<< endl;
cout << "第一种形式:" << cin.get() << endl;
cin.get(ch);
cout << "第二种形式:" <<ch << endl;
char dst[10];
cin.get(dst, 10,' ');
cout << "第三种形式:" <<dst << endl;
getline()
getline()函数用于从输入流中读取字符,直到读取到指定长度的字符或遇到终止字符时结束读取。
istream& getline(char *dst,streamsize count);//读取指定大小字符,无结束符。
istream& getline(char *dst,streamsize count,char delimiter);cin.getline(ch, 10); //实际读取9个字符
cout << "第一种形式:" << ch << endl;
cin.getline(ch1,10,'a'); //遇到字符'a'就结束读取
cout << "第二种形式:" <<ch1 << endl;read()
read()函数用于从输入流中读取指定字符个数的字符串,read()函数在读取数据时,对读取到的字节序列不作任何处理。read()函数不会识别换行符、空格等特殊字符,遇到换行符’\n’也不会结束读取。
istream& read(char *dst,streamsize count);char ch[10];
cout << "请输入一个字符串:"<< endl;
cin.read(ch, 10);
cout <<"输出:"<< ch << endl;
ignore()
ignore()函数的作用是跳过输入流中的n个字符,参数delimeter表示结束符,在跳跃过程中,如果遇到结束符就结束跳跃。ignore()函数不识别换行符、空格、制表符等特殊字符。
istream& ignore(streamsize count,char delimiter);char ch[10];
cout << "请输入一个字符串:"<< endl;
cin.ignore(1);
cin.getline(ch, 10);
cout <<"输出:"<< ch << endl;
gcount()
gcount()函数的作用是计算上一次读取到的字符个数。
streamsize gcount() const;char ch[10];
cout << "请输入一个字符串:"<< endl;
cin.ignore(1);
cin.getline(ch, 10);
cout <<"输出:"<< ch << endl;
cout <<"上次读取长度:"<< cin.gcount();
peek()
peek()函数的作用是检测输入流中待读取的字符,返回检测字符的ASCII码值。peek()函数只是检测待读取的字符,但并不会真正读取它。
int peek();char s;
cout << "请输入一个字符串:"<< endl;
s = cin.peek();
cout << "待检测字符:" << s << endl;
cin.get(s);
cout << s;
文件流
文件流是以磁盘中的文件作为输入、输出对象的数据流。输出文件流将数据从内存输出到文件中,这个过程通常称为写文件;输入文件流将数据从磁盘中的文件读入内存,这个过程通常称为读文件。
文件流对象的创建
文件流不像标准I/O流预定义了输入流对象和输出流对象,使用文件流时,需要创建文件流对象。
C++提供了三个类支持文件流的输入、输出,这三个类都包含在fstream头文件中。
- ifstream:输入文件流类,用于实现文件的输入。
- ofstream:输出文件流类,用于实现文件的输出。
- fstream:输入/输出文件流类,可同时实现文件的输入和输出。
- 无参构造
ifstream类、ofstream类和fstream类都提供了默认无参构造函数,可以创建不带参数的文件流对象。
#include <fstream>
ifstream ifs; //文件输入流对象
ofstream ofs;//文件输出流对象
fstream fs;//文件输入、输出流对象- 有参构造
在创建文件流对象时可以指定文件名和文件打开模式。
ifstream ifs("filename",ios::in);//打开模式默认是ios::in
ofstream ofs("filename", ios::out);//打开模式默认是ios::out
fstream fs("filename", ios::in|ios::out);//打开模式默认是ios::in|ios::out文件打开和关闭
文件最基本的操作就是打开和关闭,在对文件进行读写之前,需要先打开文件;读写结束之后,要及时关闭文件。
- 文件打开
- 方式一:有参构造
在创建文件流对象时传入文件名和文件打开模式即可打开文件。
- 方式二:open()
ifstream类、ostream类和fstream类都提供了成员函数open()用于打开文件,如果打开文件失败,文件流对象会变为0。
void open(const char* filename,int mode);参数mode选项如下图:

//文件打开失败
- 文件关闭
ifstream类、ostream类和fstream类都提供了成员函数close()用于关闭文件。
fstream fs("xxx.txt", ios::in);
if (!fs) {
cout << "文件打开失败" << endl;
}
fs.close();文本文件的读写
- 利用<<、>>
使用提取运算符“>>”和插入运算符“<<”。
fstream fs("xxx.txt", ios::out);
if (!fs) {
cout << "文件打开失败" << endl;
exit(0);
}
char c[40];
cout << "输入写入文件的数据:";
cin >> c;
fs << c;
fs.close();
fs.open("xxx.txt", ios::in);
char d[40];
fs >> d;
cout << endl<< "文件读取成功,内容:" << d << endl;
fs.close();
备注:文件打开后记得要关闭,不然再次打开就会有bug。
- 调用文件流类的成员函数读写文件
文件流类继承了istream类和ostream类的成员函数get()、getline()和put(),通过调用这些成员函数,文件流对象也可以完成文件的读写。
除此还有几个实用函数。
文件流成员函数 | 说明 |
bool eof() const | 检测文件是否到达末尾,是返回true |
bool bad() const | 检测文件在读写过程中是否出错 |
bool good() const | 检测文件在读写过程中是否正常 |
bool fail() const | 也用于检测在读写过程中是否出错,比bad()函数的检错范围更广泛 |
void clear(iostate state = goodbit) | 用于清除文件流的错误状态,即重置文件流的状态标志位 |
二进制文件的读写
文件流类从istream类和ostream类分别继承了write()函数和read()函数,这两个函数可以用来读写二进制文件。
#include <iostream>
#include <fstream>
using namespace std;
struct Student
{
char name[20];
int age;
char sex[5];
};
int main() {
Student stu[3];
cout << "请输入三名学生的信息(姓名 年龄 性别)" << endl;
for (int i = 0; i < 3; i++) {
cin >> stu[i].name >> stu[i].age >> stu[i].sex;
}
fstream fs("student.dat", ios::out | ios::binary);
if (!fs) {
cout << "文件打开失败";
exit(0);
}
//写入文件
for (int i = 0; i < 3; i++) {
fs.write(reinterpret_cast<char *>(&stu[i]), sizeof(stu[i]));
fs.flush();
}
fs.close();
cout << "写入成功" << endl;
fs.clear();
fs.open("student.dat", ios::in | ios::binary);
if (!fs) {
cout << "文件打开失败";
exit(0);
}
//读取文件
Student s[3];
for (int i = 0; i < 3; i++) {
fs.read(reinterpret_cast<char *>(&s[i]), sizeof(s[i]));
cout << s[i].name << s[i].age << s[i].sex << endl;
}
fs.close();
return 1;
}
每次读写一个结构体变量,由于read()函数和write()函数的第一个参数为char*类型,因此在传递参数时,需要调用reinterpret_cast<>运算符将Student结构体变量的地址转换成char*类型。
reinterpret_cast <new_type> (expression)文件随机读写
在C语言中实现文件的随机读写要依靠文件位置指针,在C++中文件的随机读写也是通过移动文件位置指针完成的。
C++文件流类提供了设置文件位置指针的函数。ifstream类提供了tellg()函数、seekg()函数。
streampos tellg(); //tellg()函数用于返回文件位置指针的位置
istream& seekg(streampos);//文件位置指针从文件开头移动streampos长度的距离
istream& seekg(streamoff,ios::seek_dir);//指定参照位置情况下,位置指针移动streamoff长度的距离参照位置 | 说明 |
ios::beg = 0 | 从文件开头开始移动 |
ios::cur = 1 | 从当前位置开始移动 |
ios::end = 2 | 从文件结尾开始移动 |
ofstream类同样提供了tellp()函数、seekp()函数用于移动文件位置指针,操作、含义都相同。
fstream fs("student.dat",ios::in|ios::binary);
cout << "当前文件指针位置:" << fs.tellp() << endl;
char c[10];
fs.read(c, sizeof(c));
cout << "读取内容:" << c << endl;
cout << "当前文件指针位置:" << fs.tellp() << endl;
fs.seekp(10,ios::cur);
cout<<"向后移动指针10长度"<< fs.tellp() << endl;
fs.close();
字符串流
字符串流是以string对象为输入/输出对象的数据流,这些数据流的传输在内存中完成,因此字符串流也称为内存流。C++提供了istringstream、ostringstream和stringstream这三个类支持string对象的输入/输出。
stringstream类的一个典型用法就是将一个数字字符串转换成对应的数值。相比于C语言的数字和字符串转换函数,stringstream类具有模板亲和性,转换效率更高而且更安全。
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
template<typename T>
T swapString(const string &str) {
stringstream s(str,ios::in); //只读模式
T t;
s >> t;
return t;
}
int main() {
cout << "12的大小:" << sizeof("12") << endl;
cout << "3.14的大小:" << sizeof("3.14") << endl;
int num = swapString<int>("12");
cout << num<<"转为int后的大小: " << sizeof(num) << endl;
double n = swapString<double>("3.14");
cout << n << "转为double后的大小: " << sizeof(n) << endl;
return 1;
}
















