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

(十)StringStream Class

1、不要用char*版本。

2、操作和fstream一模一样

成员函数

意义

str()

将缓冲区内容作为string返回

str(string)

将string设置为缓冲区内容

str(“”)

删除缓冲区

tellg()

当前读取位置

seekg(pos)

设置绝对读取位置

seekg(offset, pos)

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

 

 

tellp()

当前写入位置

seekp(pos)

绝对写入位置

seekp(offset, pos)

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

 

 

常数

意义

beg

开头

cur

当前位置

end

结尾

 

 

标志

意义

in

读取,istringstream的默认模式

out

写入,ostringstream的默认模式

app

写入时添加到尾部

ate

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

trunc

将先前的文件内容移除

binary

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

 

(十一)自定义IO操作符

1、output经典做法,以输出分数为例子:

inline std::ostream&operator << (std::ostream& strm, const Fraction& f)

{

strm << f.num() << “ / ” <<f.den();

return strm;

}

 

就一般情况而言,上面的已经足够了。但是如果要格式化输出,就会出问题。下面给出格式化输出的方法,核心思想是变化一个string,然后用iostream的方法处理string:

template <class charT, class traits>

inline

std::basic_ostream<charT , traits>&

operator << (std::basic_ostream<charT,traits>& strm, const Fraction& f)

{

std::basic_ostringstream<charT, traits> s;

s.copyfmt(strm);//复制strm的格式化标志

s.width(0);

s << f.num() << ‘/’ <<f.den();//变成string

strm << s.str();

return strm;

}

缺点就是慢。

 

2、input经典做法:

inline std::istream& operator >>(std::istream& strm, Fraction& f)

{

int n,d;

strm >> n;

strm.ignore();

strm >> d;

return strm;

}

 

就一般情况而言,上面的已经足够了。问题一样,格式化不行。同样给出全面的解法:

template <class charT, class traits>

inline

std::basic_istream<charT , traits>&

operator >> (std::basic_istream<charT,traits>& strm, Fraction& f)

{

int n,d;

strm >> n;

if(strm.peek() == ‘/’)//检查下一个字符

{

strm.ignore();

strm >> d;

}

else

{

d = 1;

}

 

if (d == 0)//分母不能是0,不然抛出异常

{

strm.setstate(std::ios::failbit);

return strm;

}

if(strm)

{

f = Fraction(n,d);

}

return strm;

}

 

缺点同样是很慢。

 

3、如果需要在类中使用私有成员,可以建立专门的读取函数:

class Fraction

{

public:

virtual printOn(std::ostream& strm);

virtual scanFrom(std::istream& strm);

}

 

inline std::istream& operator >>(std::istream& strm, Fraction& f)

{

f.scanFrom(strm);

return strm;

}

 

具体操作在类成员函数中进行。

 

4、不使用<< 和 >> ,直接进行自定义重载,利用stream的基本函数。上面的重载函数归根到底还是使用了<<和>>,这样函数自己做完了所有的工作。但是现在不用<< 和>>,这样很多工作要自己做。偷懒的方法就是使用sentry完成预备工作。

书上是用class Row来演示的,row代表文本处理的一行。重载输出函数如下:

std::ostream& operator << (std::ostream& strm,const Row& row)

{

std::ostream::sentry se(strm)

if(se)

{

strm.write(row.c_str(), row.len());

}

return strm;

}

 

5、自定义格式标志符

这里指的自定义格式符号,是独立于std::ios_base的格式符号之外的。所以我们要获取一个用户自定义空间,然后管理这个玩意儿。

static const int iword_index = std::ios_base::xalloc();//获取用户自定义位置

 

std::ostream& fraction_space(std::ostream& strm)

{

strm.iword(iword_index) = true;//设置标志位

return strm;

}

 

std::ostream& operator << (std::ostream& strm,const Fraction &f)

{

if (strm.iword(iword_index))//检查标志位

{

........

}

else

{

........

}

return strm;

}

 

copyfmt函数会复制包括iword在内的标志位。和iword一样的函数还有pword,不常用。

 

 

(十一)stream buffer

1、streambuffer是真正执行读写操作的类。你可以直接使用它来进行读写操作,速度快的与C函数有的一拼,但是烦。

2、buffer的操作和内部细节不要深究,可以学习stream bufferiterator。

3、输出缓冲区迭代器ostreambuf_iterator用法:

std::ostreambuf_iterator<char>bufWriter(std::cout);

std::stringhello(“hello world.\n”);

std::copy(hello.begin(),hello.end(), bufWriter);

 

4、输入缓冲区迭代器。其实仔细观察可以发现他们和istream_iterator的操作很像。

istreambuf_iterator<char>inpos(cin);

istreambuf_iterator<char>endpos;//结束标志符

while(inpos !=endpos)

{

++inpos;

}

 

5、

输出迭代器

代码

作用

ostreambuf_iterator<char> (ostream)

针对ostream的迭代器

ostreambuf_iterator<char>(buffer_ptr)

成为buffer_ptr缓冲区的迭代器

*iter

返回iter

iter = c

调用sputc(c),缓冲区写入字符c

++iter

返回iter

iter++

返回iter

failed()

判断迭代器是否可以改写

 

 

输入迭代器

istreambuf_iterator<char>()

结束标识符

istreambuf_iterator<char>(istream)

istream迭代器

istreambuf_itrator<char>(buffer_ptr)

成为buffer_ptr缓冲区的迭代器

*iter

返回iter

++iter

调用sbumpc()函数,读取下一个字符

iter++

调用sbumpc()函数,读取下一个字符

iter1.equal(iter2)

判断迭代器相等

iter1 == iter2

判断迭代器相等

iter1 != iter2

判断迭代器不相等 

6、streambuffer的自定义不要管啦,《stl源码剖析》也没有讲,不过估计也用不到,人家google代码规范都说不要用stream了。

7、直接使用stream缓冲区,很快,之前已经使用过了,典型例子:

std::cout<< std::cin.rdbuf();

 

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