C++之IO类,文件输入输出,string流练习题
前面已经在用的IO库设施
- istream:输入流类型,提供输入操作。
- ostream:输出流类型,提供输出操作
- cin:一个istream对象,从标准输入读取数据。
- cout:一个ostream对象,向标准输出写入数据。
- cerr:一个ostream对象,向标准错误写入消息。
- >>运算符:用来从一个istream对象中读取输入数据。
- <<运算符:用来向一个ostream对象中写入输出数据。
- getline函数:从一个给定的istream对象中读取一行数据,存入到一个给定的string对象中。
IO类
iostream
头文件:从标准流中读写数据,istream
,ostream
等fstream
头文件:从文件中读写数据,ifstream
,ofstream
等sstream
头文件:从字符串中读写数据,istringstream
,ostringstream
IO对象不能拷贝或赋值
由于不能拷贝IO对象,因此不能将 形参 或 返回类型 设置为 流类型。进行 IO 操作的函数通常以 引用方式 传递和 返回流。读写一个IO对象会改变其状态,因此 传递和返回的引用不能用const。
- IO对象不能存在容器里.
- 形参和返回类型也不能是流类型。
- 形参和返回类型一般是流的引用。
- 读写一个IO对象会改变其状态,因此传递和返回的引用不能是const的。
条件状态
状态 | 解释 |
---|---|
strm:iostate | 是一种机器无关的类型,提供了表达条件状态的完整功能 |
strm:badbit | 用来指出流已经崩溃 |
strm:failbit | 用来指出一个IO操作失败了 |
strm:eofbit | 用来指出流到达了文件结束 |
strm:goodbit | 用来指出流未处于错误状态,此值保证为零 |
s.eof() | 若流s的eofbit置位,则返回true |
s.fail() | 若流s的failbit置位,则返回true |
s.bad() | 若流s的badbit置位,则返回true |
s.good() | 若流s处于有效状态,则返回true |
s.clear() | 将流s中所有条件状态位复位,将流的状态设置成有效,返回void |
s.clear(flags) | 将流s中指定的条件状态位复位,返回void |
s.setstate(flags) | 根据给定的标志位,将流s中对应的条件状态位置位,返回void |
s.rdstate() | 返回流s的当前条件状态,返回值类型为strm::iostate |
上表中,strm是一种IO类型,(如istream), s是一个流对象。
管理输出缓冲
- 每个输出流都管理一个缓冲区,用来保存程序读写的数据。文本串可能立即打印出来,也可能被操作系统保存在缓冲区内,随后再打印。
- 刷新(即,数据真正写到输出设备或文件)缓冲区的IO操纵符
endl
:输出一个换行符并刷新缓冲区flush
:刷新流,但不添加任何字符ends
:在缓冲区插入空字符null,然后刷新unitbuf
:告诉流接下来每次操作之后都要进行一次flush操作。nounitbuf
:回到正常的缓冲方式
文件输入输出
头文件fstream定义了三个类型来支持文件IO:
ifstream
从一个给定文件读取数据。ofstream
向一个给定文件写入数据。fstream
可以读写给定文件。
fstream特有的操作
操作 | 解释 |
---|---|
fstream fstrm; | 创建一个未绑定的文件流。 |
fstream fstrm(s); | 创建一个文件流,并打开名为s的文件,s可以是string也可以是char指针 |
fstream fstrm(s, mode); | 与前一个构造函数类似,但按指定mode打开文件 |
fstrm.open(s) | 打开名为s的文件,并和fstrm绑定 |
fstrm.close() | 关闭和fstrm绑定的文件 |
fstrm.is_open() | 返回一个bool值,指出与fstrm关联的文件是否成功打开且尚未关闭 |
上表中,fstream
是头文件fstream
中定义的一个类型,fstrm是一个文件流对象。
文件模式
文件模式 | 解释 |
---|---|
in | 以读的方式打开 |
out | 以写的方式打开 |
app | 每次写操作前均定位到文件末尾 |
ate | 打开文件后立即定位到文件末尾 |
trunc | 截断文件 |
binary | 以二进制方式进行IO操作。 |
string流
头文件sstream
定义了三个类型来支持内存IO:
istringstream
从string读取数据。ostringstream
向string写入数据。stringstream
可以读写给定string。
stringstream特有的操作
操作 | 解释 |
---|---|
sstream strm | 定义一个未绑定的stringstream对象 |
sstream strm(s) | 用s初始化对象 |
strm.str() | 返回strm所保存的string的拷贝 |
strm.str(s) | 将s拷贝到strm中,返回void |
上表中sstream
是头文件sstream
中任意一个类型。s是一个string。
书中演示demo使用
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
using namespace std;
typedef struct PersonInfo
{
string name;
vector<string> phones;
}p;
int main() {
string line, word;
vector<p> people;
while (getline(cin, line))
{
p info;
istringstream record(line);
record >> info.name;
while (record >> word)
info.phones.push_back(word);
people.push_back(info);
}
for (auto i : people)
{
cout << i.name << endl;
for (auto j : i.phones)
cout << j << " ";
cout << endl;
}
return 0;
}
练习
练习1
编写函数,接受一个istream&参数,返回值类型也是istream&。此函数须从给定流中读取数据,直至遇到文件结束标识时停止。它将读取的数据打印在标准输出上。完成这些操作后,在返回流之前,对流进行复位,使其处于有效状态。
解:
std::istream& func(std::istream &is)
{
std::string buf;
while (is >> buf)
std::cout << buf << std::endl;
is.clear();
return is;
}
练习2
测试函数,调用参数为cin。
解:
#include <iostream>
using std::istream;
istream& func(istream &is)
{
std::string buf;
while (is >> buf)
std::cout << buf << std::endl;
is.clear();
return is;
}
int main()
{
istream& is = func(std::cin);
std::cout << is.rdstate() << std::endl;
return 0;
}
测试
#include <iostream>
#include <string>
using namespace std;
istream& f1(istream& is)
{
int s;
while (is >> s)
{
cout << s << endl;
}
return is;
}
istream& f2(istream& is)
{
int s;
while (is >> s)
{
cout << s << endl;
}
is.clear();
return is;
}
int main()
{
istream& is = f1(cin);
cout << is.rdstate() << endl;
istream& is2 = f2(cin);
cout << is2.rdstate() << endl;
return 0;
}
练习3
什么情况下,下面的while循环会终止?
while (cin >> i)
如badbit、failbit、eofbit 的任一个被置位,那么检测流状态的条件会失败。
练习4
编写函数,以读模式打开一个文件,将其内容读入到一个string的vector中,将每一行作为一个独立的元素存于vector中。
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
using namespace std;
void ReadFileToVec(const string& filename, vector<string>& vec)
{
ifstream ifs(filename);
if (ifs)
{
string buf;
while (getline(ifs, buf))
vec.push_back(buf);
}
}
练习5
重写上面的程序,将每个单词作为一个独立的元素进行存储。
void ReadFileToVec(const string& fileName, vector<string>& vec)
{
ifstream ifs(fileName);
if (ifs)
{
string buf;
while (ifs >> buf)
vec.push_back(buf);
}
}
练习6
编写程序,将来自一个文件中的行保存在一个vector中。然后使用一个istringstream从vector读取数据元素,每次读取一个单词。
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <vector>
using namespace std;
int main()
{
//将来自一个文件的行保存到vector中
ifstream ifs("hello.txt");
if (!ifs)
{
cerr << "no data ?" << endl;
return -1;
}
vector<string> vecline;
string line;
while(getline(ifs, line))
vecline.push_back(line);
ifs.close();
//从vector读取元素,每次只读一个单词
for (auto &s : vecline)
{
istringstream iss(s);
string word;
while (iss >> word)
cout << word << endl;
}
return 0;
}
练习7
本节的程序在外层while循环中定义了istringstream对象。如果record对象定义在循环之外,你需要对程序进行怎样的修改?重写程序,将record的定义移到while循环之外,验证你设想的修改方法是否正确。
解:
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
using std::vector; using std::string; using std::cin; using std::istringstream;
struct PersonInfo {
string name;
vector<string> phones;
};
int main()
{
string line, word;
vector<PersonInfo> people;
istringstream record;
while (getline(cin, line))
{
PersonInfo info;
record.clear();
record.str(line);
record >> info.name;
while (record >> word)
info.phones.push_back(word);
people.push_back(info);
}
for (auto &p : people)
{
std::cout << p.name << " ";
for (auto &s : p.phones)
std::cout << s << " ";
std::cout << std::endl;
}
return 0;
}
练习8
我们为什么没有在PersonInfo中使用类内初始化?
解:
因为这里只需要聚合类就够了,所以没有必要在PersionInfo中使用类内初始化。
练习9
电话号码程序
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <vector>
using namespace std;
struct PersonInfo {
string name;
vector<string> phones;
};
bool valid(const string& str)
{
return isdigit(str[0]);
}
string format(const string& str)
{
return str.substr(0, 3) + "-" + str.substr(3, 3) + "-" + str.substr(6);
}
int main()
{
//从文件中读取信息存入vector容器
ifstream ifs("phone.txt");
if (!ifs)
{
cerr << "no phone numbers ? " << endl;
return -1;
}
vector<PersonInfo> people;
string line, word;
istringstream record;
while (getline(ifs, line))
{
PersonInfo info;
record.clear();
record.str(line);
record >> info.name;
while (record >> word)
{
info.phones.push_back(word);
}
people.push_back(info);
}
//逐个验证电话号码 并 改变其格式
for (const auto& entry : people) //对people中的每一项
{
//每个循环创建的对象
ostringstream formatted, badnums;
//对每个数
for (const auto& nums : entry.phones)
{
if (!valid(nums))
{
badnums << " " << nums;
//将数的字符串形式存入badnums
}
else
{
//将格式化的字符串写入formatted
formatted << " " << format(nums);
}
}
//没有错误的数
if (badnums.str().empty())
{
cout << entry.name << " "
<< formatted.str() << endl;
}
else
{
//打印名字和错误的数
cerr << "input error: " << entry.name
<< " invalid number(s)" << badnums.str() << endl;
}
}
return 0;
}
总结
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注编程网的更多内容!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341