IO库
1 IO类
常用的IO库类型和头文件如下表:
头文件 | 类型 |
---|---|
iostream | istream ,wistream 从流读取数据 |
ostream ,wostream 向流写入数据 | |
iostream ,wiostream 读写流 | |
fstream | ifstream ,wifstream 从文件读取数据 |
ostream ,wofstream 向文件写入数据 | |
fstream ,wfstream 读写文件 | |
sstream | istringstream ,wistringstream 从string读取数据 |
ostringstream ,wostringstream 向string写入数据 | |
stringstream ,wstringstream 读写string |
w开头的表示宽字符类型
1.1 条件状态
名称 | 描述 |
---|---|
strm::iostate | strm 是一种IO类型,在上表中已列出 |
strm::badbit | 用来指出流已经崩溃 |
strm::failbit | 用来指出一个IO操作失败了 |
strm::eofbit | 用来指出流到达了文件结束 |
strm::goodbit | 用来指出流未处于错误状态 |
s.eof() | 若流s的eofbit 置位,则返回true |
s.fail() | 若流s的failbit 或badbit 置位,则返回true |
s.bad() | 若流s的badbit 置位,则返回true |
s.good() | 若流s处于有效状态,则返回true |
s.clear() | 将流s中所有条件状态复位,将流的状态设置为有效。返回void |
s.clear(flags) | 根据给定的flag标志位,将流s中对应条件状态位复位。flag类型为strm::iostate |
s.setstate(flags) | 根据给定的flag标志位,将流s中对应条件状态位置位。flag类型为strm::iostate |
s.rdstate() | 返回流s的当前条件状态,返回类型为strm::iostate |
1.2 管理输出缓冲
每一个输出流都管理一个缓冲区,用来保存程序读写的数据。其中导致缓冲区刷新的原因有如下几种:
- 程序正常结束
- 缓冲区满时,需要刷新缓冲区,后面新来的数据才能继续写入缓冲区
- 使用操作符如endl来显示刷新缓冲
- 在每个输出操作之后,可以用操作符unitbuf设置流的内部状态,来清空缓冲区
- 一个输出流可能被关联到另一个流,当读写被关联的流时,关联到的流的缓冲区会被刷新
刷新输出缓冲区操作符:flush和ends,其中flush刷新缓冲区,但不输出任何额外的字符;ends向缓冲区插入一个空字符,然后刷新缓冲区。
2 文件输入输出
头文件fstream
定义了三个类型来支持文件IO:ifstream
从一个给定文件读取数据,ofstream
向一个给定文件写入数据,fstream
可以读写给定文件
名称 | 描述 |
---|---|
fstream fstrm; | 创建一个未绑定的文件流 |
fstream fstrm(s); | 创建一个fstream ,并打开名为s的文件,s可以是string类型,或指向C风格字符串的指针 |
fstream fstrm(s, mode); | 创建一个fstream ,并打开名为s的文件,按指定mode打开文件 |
fstrm.open(); | 打开名为s的文件,并将文件与fstrm 绑定 |
fstrm.close(); | 关闭与fstrm 绑定的文件。返回void |
fstrm.is_open(); | 返回一个bool 值,表示与fstrm 关联的文件是否打开成功并且尚未关闭 |
示例:
ifstream in(ifile); //创建一个ifstream并打开给定文件
ofstream out; //输出文件流
out.open(ifile + ".txt"); //打开指定文件
2.1 文件模式
操作 | 描述 |
---|---|
in | 以读方式打开文件 |
out | 以写方式打开文件 |
app | 每次写操作前均定位到文件末尾 |
ate | 打开文件后立即定位到文件末尾 |
trunc | 截断文件 |
binary | 以二进制方式进行IO |
指定文件模式有如下限制:
- 只可以对
ofstream
或fstream
对象设定out模式 - 只可以对
ifstream
或fstream
对象设定in模式 - 只有当out也被设定时,才可设定trunc模式
- ate和binary模式可用于任何类型的文件流对象,且可以与其他任何文件模式组合使用
- 只要trunc没有被设定。就可以设定app模式。在app模式下即使没有显式指定out模式,文件也总是以输出方式被打开。
- 即使没有指定trunc,以out模式打开的文件也会被截断,因此为保留此时的内容,必须同时指定app模式,这样数据将追加写到文件末尾
Tips:当打开一个ofstream
时文件的内容会被丢弃,因此此时必须显式指定app或in模式
示例如下:
//文件内容会被截断
ofstream app("file2");
ofstream app("file2", ofstream::out);
//文件内容保留
ofstream app("file2", ofstream::app);
ofstream app("file2", ofstream::out | ofstream::app);
3 string流
名称 | 描述 |
---|---|
sstream strm; | strm 是一个未绑定的stringstream 对象。sstream 是头文件sstream 中定义的一个类型 |
sstream strm(s); | strm 是一个sstream 对象,保存string s 的一个拷贝 |
strm.str() | 返回strm 所保存的string的拷贝 |
strm.str(s) | 将string s 拷贝到strm 中,返回void |
3.1 使用istringstream
示例如下:
现有一个这样的文件,其输入格式如下:
morgan 2015552368 8625550123
drew 9735550130
lee 6095550132 2015550175 8005550000
首先定义一个简单的类来描述输入数据:
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); //将此记录追加到people末尾
}
这里的istringstream
将getline
读取的文本进行绑定,然后在istringstream
上使用输入运算符来读取当前记录中的每个元素,即元素之间以空格为区分。
3.2 使用ostringstream
对于上例,现将每个人的电话打印出来,但是不希望输出无效电话号码的人,因此需要进行验证。此时可以先将要输出的内容“写入”到一个内存ostringstream
中,其代码如下:
for(const auto &entry : people) //对people中的每一项
{
ostringstream formatted,badNums; //每个循环步创建的对象
for(const auto &num : entry.phones) //对每个数
{
if(!valid(nums))
{
badNums << " " << nums; //将数的字符串形式存入badNums
}
else
formatted << " " << format(num); //将格式化的字符串“写入”formatted
}
if(bad.Nums.str().empty()) //没有错误的数
//打印名字和格式化的数
os << entry.name << " " << formatted.str() << endl;
else//打印名字和错误的数
ceer << "input error: " << entry.name
<< " invalid number(s)" << badNums.str() << endl;
}