需要一个一个字符输入时考虑使用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 就会结束,会丢弃后面的字符。

使用 istreambuf_iterator 读取文件内容,赋值给 std::string的更多相关文章

  1. shell读取文件内容并进行变量赋值

    需求: shell读取文件内容,然后把内容赋值给变量然后进行字符串处理 实现: dataline=$(cat /root/data/data.txt) echo $dataline

  2. 使用while和read命令读取文件内容

    转:使用while和read命令读取文件内容 1.准备数据文件 $cat a.txt 200:2 300:3 400:4 500:5 2.用while循环从文件中读取数据 #!/bin/ksh whi ...

  3. shell读取文件内容

           Shell脚本,执行解释速度快.代码简单易于理解.在shell代码编写过程中,经常会用到读取文件内容. 写法一: ------------------------------------ ...

  4. Python跳过第一行读取文件内容

    Python编程时,经常需要跳过第一行读取文件内容.比较容易想到是为每行设置一个line_num,然后判断line_num是否为1,如果不等于1,则进行读取操作.相应的Python代码如下: inpu ...

  5. 用c#读取文件内容中文是乱码的解决方法:

    用c#读取文件内容中文是乱码的解决方法: //方法1: StreamReader din = new StreamReader(@"C:\1.txt", System.Text.E ...

  6. android按行读取文件内容的几个方法

    一.简单版 import java.io.FileInputStream; void readFileOnLine(){ String strFileName = "Filename.txt ...

  7. android逐行读取文件内容以及保存为文件

    用于长时间使用的apk,并且有规律性的数据 1,逐行读取文件内容 //首先定义一个数据类型,用于保存读取文件的内容 class WeightRecord { String timestamp; flo ...

  8. 7 RandomAccessFile读取文件内容保存--简单例子(需要验证)

    import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.*; /** * 读取动态产生的文件内容 */ publ ...

  9. node遍历文件夹并读取文件内容

    var fs = require('fs'); var path = require('path');//解析需要遍历的文件夹 var filePath = path.resolve('./dist' ...

随机推荐

  1. apt-get build-dep

    apt-get 里面有个 build-dep参数,手册写着:build-dep causes apt-get to install/remove packages in an attempt to s ...

  2. 20145334赵文豪 WEB基础实践

    实验问题回答 1.什么是表单 表单在网页中主要负责数据采集功能 一个表单有三个基本组成部分: 表单标签 表单域:包含了文本框.密码框.隐藏域.多行文本框.复选框.单选框.下拉选择框和文件上传框等 表单 ...

  3. UVa 1451 Average - 斜率优化

    A DNA sequence consists of four letters, A, C, G, and T. The GC-ratio of a DNA sequence is the numbe ...

  4. poj 3368 Frequent values -Sparse-Table

    Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 16537   Accepted: 5981 Description You ...

  5. git 指定要提交的ssh key

    问题描述 ssh具有-i选项,用于告知在验证时使用哪个私钥文件: -i identity_file Selects a file from which the identity (private ke ...

  6. IntelliJ-IDEA和Git、GitHub、Gitlab的使用

    一.基本入门 1.IntelliJ-IDEA预装的版本控制介绍 我们来看IntelliJ-IDEA的版本控制设置区域 打开File>Settings>Version Control  可以 ...

  7. require的压缩命令

    注意点 node r.js -o baseUrl=js name=main out=js/build.js paths.jquery=empty: 注:baseUrl是可选的 取决于页面是否有写这个入 ...

  8. 【TCP/IP详解 卷一:协议】第十二章 广播与多播 ping实验

    我手机连接到wifi上所分配到的IP地址:192.168.1.116 子网掩码:255.255.255.0 路由器:192.168.1.1 ping 192.168.1.116 (ping 一台主机的 ...

  9. 发现 一个 http 压测库

    代码库:https://github.com/wg/wrk 安装 https://github.com/wg/wrk

  10. for循环,定时器,闭包混合一块的那点事。

    1,对于一个基本的for循环,顺序输出变量值. for(var i = 1; i < 4; i++){ console.log(i);//结果不多说了吧 } 2,如果for循环中有定时器,如下代 ...