知识点:
1. C++总体来说有三种输入输出流:第一种标准的输入输出,第二种是文件的输入输出,第三种是基于字符串的输入输出。 C++引入IO流,将这三种输入输出流接口统一起来,使用>>读取数据时,不用去管是从何处读取字符,使用<<写数据的时候也不需要管是写到哪里去。
2. cin(cout) 是一个实例化的istream(ostream)对象,从标准输入(输出)读取(写入)数据。实例化在main函数之前。
3. 不能对IO对象进行拷贝或赋值。因此不能将形参或返回类型设置为流类型,进行IO操作的函数通常以引用 方式传递和返回流。读写一个IO对象会改变其状态,因此传递和返回的引用不能是const的。
4. IO类所定义的一些函数和标准,可以帮助我们访问和操纵流的条件状态。
5. 一个流一旦发生错误,后续的IO操作都会失败。只有当一个流处于正确状态时,我们才可以从它读取数据,向它写入数据。确定一个流对象的状态最简答的办法是将它当作一个条件来使用,如while(cin>>word)
6. 实际上,我们将流当作条件使用的代码就等价于!fail()。
7. 导致缓冲刷新的原因有很多:缓冲区满,流状态设定,程序结束时,endl等操作符。
8. 关于endl: 完成换行并刷新缓冲区的工作。 flush:只刷新缓冲区,不做任何操作。 ends:输出空字符并刷新缓冲区。
9. 如果程序异常终止,输出缓冲区是不会被刷新的。当一个程序奔溃后,它所输出的数据很可能停留在输出缓冲区中等待打印。
10. 头文件fstream定义了三个类型来支持文件IO:ifstream从一个给定的文件读取数据,ofstream向一个给定文件写入数据,fstream可以读写给定文件。
11. fstream
是头文件
中定义的一个类型,
有很多的特有操作,当我们想读写一个文件时,可以定义一个文件流对象,并将对象与文件关联起来。每个文件流类都定义了一个名为open的成员函数,它来定位给定的文件,并按照情况打开读或写模式。创建文件流对象时,我们可以提供文件名。如果提供了一个文件名,则open会被自动调用。解释下: fstream fstrm; 创建一个未绑定的文件流(对象),可以随后调用open将它与文件关联起来。而
ifstream
fstrm(
fName)变直接调用绑定到fName文件并自动调用open函数。
12. 类型ifstream 和 istringstream 都继承自istream。
13. 因为调用open 函数可能失败,通常进行open是否成功的检测 。
14.当一个fstream 对象被销毁时,close 函数会自动被调用。
15.
fstream 类中有一个构造函数 fstream fileName(s,mode) mode 是关联的文件模式,按指定的 mode 打开文件,默认是依赖于fstream 类型(一般有in:以读方式; out :以写方式等等...)。 默认模式:与ifstream 关联的文件默认以in模式打开; 与ofstream 关联的文件默认以out 模式打开; 与fstream 关联的文件默认以 in 和out 模式打开。
16. ofstream 默认的out 打开方式会阶段文件,唯一保留数据方式是显示指定 app 或 in 模式。
17. 每次打开文件时,都要设置文件模式,可能是显式地设置,也可能是隐式地设置。未指定时,采用默认方式。
18. 关于cin>>ci; cin 本身是输入流对象,1 通过键盘获取数据,2 通过>> 流提取运算符(读入)数据,3 将数据赋给ci变量。
而cout << co; cout是输出流对象,1通过<< 流插入运算符,将数据插入到cout输出流中,2 在将数据从输出流对象中输出到指定设备(屏幕)。因为cin和cout是与键盘屏幕等连接的所以,输入输出便指这两样。而8_07,8_08,是自定义的fstream对象,可以从一个文件读入数据,将数据打印(写)打印到另一个文件中。
19. string 流 :sstream头文件定义了三个类型来支持内存IO,可以向string写数据,读数据;看起来string是以IO流一样。有一些独有的操作:
sstream strm(s); strm 是一个sstream对象,保存string s的一个拷贝,此构造函数是explicit。strm.str(); 返回strm所保存的string(s)的拷贝.
20. isotream 处理控制台IO; fstream 处理命名文件IO; stringstream 完成内存string 的IO; 而类fstream 和stringstream 都是继承自类 iostream 的。所以在iostream 对象上执行的操作,也可以在 fstream 和 stringstream 操作。
21 每个IO 对象都维护一组条件状态,用来指出此对象上是否可以进行IO操作。如果遇到了错误——例如再输入流上遇到文件末尾,则对象的状态变为失效,所有后续输入操作都不能执行,直至错误被纠正。标注库提供了一组函数,用来设置和检测这些状态。
习题:
8.03 答:当流的状态出错时,即eof, bad,fail 显示出错的标志时。
8.12 答:暂时没想好怎么回答。
8.14 答:entry与nums都不是内置类型,没有定义相应的拷贝函数,用引用快,安全。不允许被修改用户的数据,所以加const。
程序题:
题:8_01, 8_04, 8_05
#include
<iostream>
#include
<string>
#include
<vector>
#include
<fstream>
using
namespace
std;
//返回类型和形参都为istream&,返回对流状态复位
istream &fun8_01(istream &c)
{
string st;
c>>st;
cout<<st<<endl;
c.clear();
return
c;
}
//从文件读入数据,并存储到vector中
void
fun8_04(
const
string &fName, vector<string> &svec1)
{
string cs;
ifstream f1(fName);
if
(f1)
//注意加判断
{
while
(getline(f1,cs))
{
svec1.push_back(cs);
}
}
}
//8.04的基础上将每个元素独立存储
void
fun8_05(
const
string fname, vector<string> &svec2)
{
fstream f2(fname);
string word;
if
(f2)
{
//f2是个流对象, 可以对比cin,不过cin是面向键盘,f2是连接该文件,所以>>
//是f2流往word变量里一个一个忽略空格回车,输出单词
while
(f2>>word)
svec2.push_back(word);
}
}
int
main(
int
argc,
char
*argv[])
{
//cout<<fun8_01(cin).rdstate();
vector<string> svec;
//fun8_04("D:/abc.txt",svec);这里地址注意是以/划分,而不是拷贝而来的\。
int
i = 0;
fun8_05(
"D:/abc.txt"
,svec);
for
(
auto
it = svec.begin(); it!=svec.end(); ++it)
{
++i;
cout<<
"第"
<<i<<
"词 :"
<<*it<<endl;
}
return
0;
}
题:8_06
#include
<fstream>
#include
"D:/Sales_data.h"
int
main(
int
argc,
char
*argv[])
{
ifstream input(
"D:/abc.txt"
);
Slaes_data total;
if
(read(input, total)) {
Slaes_data trans;
while
(read(input, trans)) {
if
(total.isbn() == trans.isbn())
else
{
prin(std::cout, total) << std::endl;
total = trans;
}
}
prin(std::cout, total) << std::endl;
}
else
{
std::cerr <<
"No data?!"
<< std::endl;
}
return
0;
}
题:8_07, 8_08
#include
<fstream>
#include
"D:/Sales_data.h"
int
main(
int
argc,
char
*argv[])
{
ifstream input(
"D:/abc.txt"
);
ofstream output(
"D:/cba.txt"
, ofstream::app);
Slaes_data total;
if
(read(input, total)) {
Slaes_data trans;
while
(read(input, trans)) {
if
(total.isbn() == trans.isbn())
else
{
prin(output, total) << std::endl;
total = trans;
}
}
//这里的打印不再打印在屏幕上,而是直接输出到与putput关联的文件中。
prin(output, total) << std::endl;
}
else
{
std::cerr <<
"No data?!"
<< std::endl;
}
return
0;
}
题:8_09
#include
<iostream>
#include
<string>
#include
<vector>
#include
<sstream>
using
namespace
std;
//接受并打印istringstream的内容
istream &fun8_09(istringstream &c)
{
string st;
c>>st;
cout<<st<<endl;
c.clear();
return
c;
}
int
main(
int
argc,
char
**argv)
{
istringstream ms(
"hallo 2018"
);
fun8_09(ms);
//结果输出hallo,所以string流可以应用在一行中挨个输出单词。
return
0;
}
题:8_10
#include
<iostream>
#include
<string>
#include
<vector>
#include
<fstream>
#include
<sstream>
using
namespace
std;
//从文件读一行,然后用vector保存
void
fun8_10(
const
string &fName, vector<string> &sec1)
{
string line;
ifstream f1(fName);
if
(f1)
{
while
(getline(f1,line))
sec1.push_back(line);
}
}
int
main(
int
argc,
char
**argv)
{
vector<string> sec;
fun8_10(
"D:/abc.txt"
, sec);
//用istringstram流 读取行中内容,然后输出
for
(
auto
it=sec.begin(); it!=sec.end(); ++it)
{
istringstream s(*it);
string word;
while
(s>>word)
cout<<
" "
<< word<<endl;
}
return
0;
}
题:8_11
#include
<iostream>
#include
<vector>
#include
<string>
#include
<sstream>
#include
<fstream>
using
namespace
std;
class
personInfo
{
public
:
string name;
vector<string> phones;
};
int
main(
int
argc,
char
**argv)
{
ifstream f1(
"D:/cba.txt"
);
vector<personInfo> p1;
string line;
if
(f1)
{
istringstream record;
record.clear();
while
(getline(f1,line))
{
personInfo Info;
string word;
record.str(line);
record>>Info.name;
while
(record>>word)
Info.phones.push_back(word);
p1.push_back(Info);
record.clear();
}
}
for
(
auto
it=p1.begin(); it!=p1.end(); ++it)
{
cout<<endl<<it->name<<
" :"
<<endl;
for
(
auto
p1 = it->phones.begin(); p1!=it->phones.end(); ++p1)
cout<<(*p1)<<endl;
}
return
0;
}
题:8_13 (因为8_11 是从文件读取,所以这里只需修改上一题的输出,输出到文件即可)
ofstream f2(
"D:/aaa.txt"
);
for
(
auto
it=p1.begin(); it!=p1.end(); ++it)
{
f2<<endl<<it->name<<
" :"
<<endl;
for
(
auto
p1 = it->phones.begin(); p1!=it->phones.end(); ++p1)
f2<<(*p1)<<endl;
}
return
0;