使用 istreambuf_iterator 读取文件内容,赋值给 std::string

需要一个一个字符输入时考虑使用istreambuf_iterator

假设我们要把一个文本文件拷贝到一个字符串对象中。似乎可以用一种很有道理的方法完成:

ifstream inputFile("d:\\test.plist");
string fileData((istream_iterator<char>(inputFile)), istream_iterator<char>());   
//为什么它不是很正确看下文
//关于这个语法的警告,参见条款6

很快你就会发现这种方法无法把文件中的空格拷贝到字符串中。那是因为istream_iterators使用operator<<函数来进行真的读取,而且operator<<函数在默认情况下忽略空格。

假如你想保留空格,你要的做就是覆盖默认情况。只要清除输入流的skipws标志就行了:

ifstream inputFile("d:\\test.plist"); 
inputFile.unset(ios::skipws); // 关闭inputFile的忽略空格标志 
string fileData((istream_iterator<char>(inputFile)), istream_iterator<char>());

现在inputFile中的所有字符都拷贝到fileData中了。

此时,你会发现它们的拷贝速度不像你想象的那么快。

istream_iterators所依靠的operator<<函数进行的是格式化输入,这意味着,每次你调用的时候它们都必须做大量工作。它们必须建立和销毁sentry对象(为每个operator<<调用进行建立和清除活动的特殊的iostream对象),

它们必须检查可能影响它们行为的流标志(比如skipws),它们必须进行全面的读取错误检查,而且如果它们遇到问题,它们必须检查流的异常掩码来决定是否该抛出一个异常。

如果进行格式化输入,这些都是重要的活动,但如果你需要的只是从输入流中抓取下一个字符,这样做就过度了。

 

一个更高效的方法是使用STL最好的秘密武器之一:istreambuf_iterators。

你可以像istream_iterator一样使用istreambuf_iterator。

istreambuf_iterator<char>对象进入流的缓冲区,并直接读取下一个字符。(更明确地说,一个istreambuf_iterator<char> 对象从一个istream s中读取会调用s.rdbuf()->sgetc()来读s的下一个字符。)

把我们的文件读取代码改为使用istreambuf_iterator相当简单:

ifstream inputFile("d:\\test.plist"); 
string fileData((istreambuf_iterator<char>(inputFile)), istreambuf_iterator<char>());

 

注意这里不需要“unset”skipws标志,istreambuf_iterator不忽略任何字符。它们只抓取流缓冲区的下一个字符。

相对于istream_iterator,它们抓取得更快——在我进行的简单测试中能快40%,如果你的结果不同也不用惊奇。如果随时间流逝,速度优势不断增加也不必奇怪,

因为istreambuf_iterator存在于STL的一个不常访问的角落,所以实现还没有花很多时间来优化。

比如,在我用过的一个实现中,istreambuf_iterator在我的主要测试中只比istream_iterator快了大约5%。那样的实现显然还有很多余地来优化它们的istreambuf_iterator实现。

如果你需要一个一个地读取流中的字符,你不需要格式化输入的威力,你关心的是它们花多少时间来读取流,和明显的性能提高相比,为每个迭代器多键入三个字符的代价是微弱的。

对于无格式的一个一个字符输入,你总是应该考虑使用istreambuf_iterator。

 

完整代码如下;

#include <iostream>
#include <fstream>  
#include <streambuf>

std::ifstream file(“d:\\test.plist”);
if (!file.is_open())
 {
     return NULL;
}
std::string content;
content.assign(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());

 

注:另外有的程序员使用 ifstream 读取文件内容,然后直接赋值给std::string对象,肯定是错误的。因为:读取的char*类型赋值给string时,默认遇到 \0 就会结束,会丢弃后面的字符。

 

转载于:https://www.cnblogs.com/pjl1119/p/8488344.html

  • 7
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值