《C++标准程序库》小结第十三章-stream(2)

(五)标准输入函数

1、输入函数。cin<<函数只适用于非格式化输入。下面是另外一些输入函数。注意其中有一些是cin的成员函数!!!getline有两种用法cin.getline(s,num)或者getline(cin,s,num);

成员函数

读取直到遇到...

字符数

添加结束符

返回

get(s,num)

EOF,不包括EOF

最多num-1

istream

get(s,num,t)

t或EOF,不包括t和EOF

最多num-1

istream

getline(s,num)

包括EOF

最多num-1

istream

getline(s,num,t)

包括t或EOF

最多num-1

istream

read(s,num)

EOF

num

istream

readsome(s,num)

EOF

最多num

count

gcount

 

 

 

返回上次非格式化读取操作所读入的字符数

ignore()

 

 

 

忽略一个字符

ignore(count)

 

 

 

忽略count个字符

ignore(count, delim(单个字符))

 

 

 

忽略count个字符直到delim,舍弃delim

peek()

 

 

 

获取即将读取的下一个字符,但不会读入缓冲区

unget()

 

 

 

把上一次读取的字符放回stream缓冲区。如果没有错误,下一次可以读取它。

putback(char c)

 

 

 

检查c是否是上一次读取的字符,如果是就执行unget(),不是就设立badbit甚至抛出异常

 

2、get与getline区别不是很大,但一个明显的区别是get遇到 '\n '字符后便返回,这是 '\n '还在缓冲区中,所以下次读出来的将是 '\n ',解决之道是在第一次调用完cin.get()以后再调用一次cin.get()把'\n'符给读取了,可以组合式地写为cin.get(name,SIZE).get();。而getline遇到 '\n '也返回,但它会把 '\n '从缓冲区里移除掉 所以很多时候用getline方便些。

3、read函数,不会自动加结束符号,要手动添加,否则会出问题,例子如下:

char c[5];

c[4] = 0;//必须手动,否则输出末尾会带有乱码!

cin.read(c, 4);//就算强制输入5个字符,也只会放入4个字符。

cout << c <<endl;

 

4、上面的成员函数适用于char字符串,比>>要安全,因为明确指定了范围。

5、以下操作会舍弃当前这一行剩余部分:

cin.ignore(numeric_limits<std::streamsize>::max(), ‘\n’);

以下操作舍弃cin所有剩余部分:

cin.ignore(numeric_limits<std::streamsize>::max());

6、直接用stream buffer性能比成员函数好,因为不需要构造sentry对象。另一种方法是使用迭代器istreambuf_iterator。相关内容将在后面提到。

 

(六)标准输出函数

成员函数

作用

返回。可以获取返回ostream的状态来监视操作是否成功

put(char c)

把c写到stream

ostream&

write(const char* str, count)

将str中的count个字符写入stream,但不会在EOF处停止

ostream&

flush()

刷新stream缓冲区,把缓冲区数据全部强制写入设备

ostream&

直接使用streambuffer或者迭代器ostreambuf_iterator效率更高。但是要注意多线程环境下的上锁机制。

 

对比C函数:int getc(FILE *stream);把数据作为int传回。也可直接转为char。

char ch;

ch = getc(stdin);

int getchar(void);相当于getc(stdin);

返回值可能是EOF,这个需要自己手动判断,C++标准函数已经提供了自动判断,所以用C++的要安全。

char *gets(char*)        // 可以接受一个string,可以接收空格并输出,需包含“#include<string>”

 读入成功,返回与参数buffer相同的指针;读入过程中遇到EOF(End-of-File)或发生错误,返回NULL指针。所以在遇到返回值为NULL的情况,要用ferror或feof函数检查是发生错误还是遇到EOF。本函数可以无限读取,不会判断上限,所以程序员应该确保buffer的空间足够大,以便在执行读操作时不发生溢出。如果溢出,多出来的字符将被写入到堆栈中,这就覆盖了堆栈原先的内容,破坏一个或多个不相关变量的值,为了避免这种情况,我们可以用fgets()来替换gets()。这个事实导致gets函数只适用于玩具程序。在V7的手册(1979年)中说明:为了向后兼容,gets删除换行符,gets并不将换行符存入缓冲区。

 

(七)操控器

1、直接跟在<<或者>>后面的。

操控器

类别

作用

flush

basic_ostream

刷新输出缓冲区,强制写入设备

endl

basic_ostream

向缓冲区插入换行符号并刷新

ends

basic_ostream

向缓冲区插入终止符号

ws

basic_istream

读取时忽略空格

2、一般形式:

ostream& ostream::operator<<(ostream& (*op)(ostream&))

{

return(*op)(*this);

}

简单来说就是调用<<后面的函数指针,对自身进行操作。

比如endl:

std::ostream&std::endl(std::ostream& strm)

{

strm.put(‘\n’);

strm.flush();

return strm;

}

 

3、自定义模板操控器例子:

template<classcharT, class traits>

inlinestd::basic_istream<charT, traits>& ignoreLine(std::basic_istream<charT, traits>& strm)

{

strm.ignore(std::numeric_limits<int>::max(), strm.widen(‘\n’));

return strm;

}

用法:省略两行

std::cin>> ignoreLine >> ignoreLine;

 

 

(八)格式标志函数

成员函数

作用

setf(flag)

设置格式标志flag,返回所有原始标志

setf(flag,mask)

配合掩码mask设置flag,返回所有原始标志

unsetf(flag)

清除flag

flags()

返回所有已经设立的标志

flags(flag)

以参数flag为新标志,并返回旧标志

copyfmt(stream)

从stream中复制所有格式定义

std::ios::basefield是数学进制的掩码,例子:

std::cout.setf(std::ios::hex,std::ios::basefield);

清除所有进制标志,并设立hex标志。

 

一个实际应用:

ios::fmtflags oldFlags = cout.flags()

cout.setf(std::ios::showpos | std::ios ::uppercase);

cout << std::hex << x<<std:: endl;

cout.flags(oldFlags);

 

另外也可以使用操控器

操控器

作用

setiosflags(flag)

相当于setf(flag)

resetiosflags(mask)

清除mask标记的一组标志相当于setf(0,mask)

用法:

#include <iomanip>//使用操控器必须添加

 

cout <<resetiosflags(std::ios::adjustfield)

<<setiosflags(std::ios::left);

 

各类操控器和格式化输出函数请查阅P616-626

 

(九)文件存取

1、C++文件流,可以手动关闭,可以不用关闭(自动关闭)。但是如果使用了指针,就需要自己删除。

2、文件标志

标志

意义

in

读取,ifstream的默认模式

out

写入,ofstream的默认模式

app

写入时添加到尾部

ate

读写时,读写位置移动到文件末尾

trunc

将先前的文件内容移除

binary

不替换特殊字符,这样可以保留其他系统文件格式。如果是二进制文件也应该用他

 

与C函数不同,C函数fopen的标志位必须要设置为a或者a+才不会覆盖原始文件。

组合用法

意义

C函数

in

读取

r

out

清空然后改写

w

out|trunc

清空然后改写(和上面意义)

w

out|app

添加

a

in|out

读写,位置在起点

r+

in|out|trunc

先清空再读写

w+

 

成员函数

成员函数

意义

open(name)

缺省模式打开

open(name, flag)

以flag模式打开

close()

关闭

is_open()

判断是否打开

 

2、多次使用流对象

ifstream file;

for(int i = 0; i <argc; ++i) {

file.open(argv[i]);

char c;

while(file.get(c)) {

cout.put(c);

}

 

//另外一种输出方式

std::cout << file.rdbuf();//更快!!

 

file.clear();//这个很重要!!!

file.close();

}

 

3、随机读取,g表示get, p表示put。注意函数不会检查是否越界!!!

成员函数

意义

tellg()

当前读取位置

seekg(pos)

设置绝对读取位置

seekg(offset, pos)

设置相对pos的偏移读取位置

 

 

tellp()

当前写入位置

seekp(pos)

绝对写入位置

seekp(offset, pos)

设置相对pos的偏移写入位置

 

4、位置常数

常数

意义

beg

开头

cur

当前位置

end

结尾

用法:

file.seekg(20,std::ios::cur);

 

5、如果想这样干:执行某个流操作,但想同时自动刷新其他某个流的缓冲区。使用tie函数。

成员函数

意义

tie()

返回当前连接的strm

tie(ostream *strm)

连接strm,自动刷新strm

tie(0), tie(NULL)

取消tie

std::cin.tie(&std::cout);

std::cout << “....”;

std::cin >> x;//自动清空cout缓冲区

std::cin.tie(static_cast<std::ostream*>(0));//取消tie

 

6、缓冲区紧耦合

成员函数

意义

rdbuf()

返回stream缓冲区

rdbuf(streambuf*)

把streambuf缓冲区安装到当前流,并返回当前流的原始缓冲区

注意缓冲区的原来的主人析构的时候会连带析构缓冲区,所有记得把自己的缓冲区还原。

streambuf *oldbuffer = strm.rdbuf();

strm.rdbuf(file.rdbuf);

操作

....

strm.rdbuf(oldbuffer);//还原

你可能感兴趣的:(《C++标准程序库》小结第十三章-stream(2))