我想将文件读成字符串。我正在寻找有效的方法。
使用固定大小的* char缓冲区
我收到了来自Tony的answer,它创建了一个16 kb缓冲区并读入该缓冲区并附加缓冲区,直到没有其他内容可读。我理解它是如何工作的,我发现它非常快。我不明白的是,在答案的评论中,据说这种方式将所有内容复制两次。但据我所知,它只发生在内存中,而不是发生在磁盘上,所以它几乎是不可察觉的。它是从缓冲区复制到内存中的字符串的问题吗?
使用istreambuf_iterator
我收到的other answer使用了istreambuf_iterator。代码看起来美观而且极小,但速度极慢。我不知道为什么会这样。为什么那些迭代器这么慢?
使用memcpy()
对于this question我收到的评论是我应该使用memcpy(),因为它是最快的本机方法。但是如何将memcpy()与字符串和ifstream对象一起使用?是不是ifstream应该使用自己的读取功能?为什么使用memcpy()破坏可移植性?我正在寻找与VS2010以及GCC兼容的解决方案。为什么memcpy()不适用于那些?
+还有其他任何有效方法吗?
你推荐什么,我使用什么外壳,小< 10 MB二进制文件?
(我不想将这个问题分成几部分,因为我对如何将ifstream读入字符串的不同方式之间的比较更感兴趣)
答案 0 :(得分:9)
它只发生在内存中,而不是发生在磁盘上,所以它几乎是不可察觉的
这确实是正确的。不过,一个不这样做的解决方案可能会更快。
为什么那些迭代器这么慢?
代码很慢,不是因为迭代器,而是因为字符串不知道要分配多少内存:istreambuf_iterator
只能被遍历一次所以字符串基本上被强制执行重复的连接与结果内存重新分配,非常慢。
我最喜欢的单行,来自another answer直接从底层缓冲区流式传输:
string str(static_cast<stringstream const&>(stringstream() << in.rdbuf()).str());
在最近的平台上,这确实会预先分配缓冲区。但是它仍然会产生冗余副本(从stringstream
到最终字符串)。
答案 1 :(得分:4)
最常见的方式可能是使用的响应
istreambuf_iterator
:
std::string s( (std::istreambuf_iterator<char>( source )),
(std::istreambuf_iterator<char>()) );
虽然确切的性能非常依赖于实现,但它是 这是最快的解决方案。
一个有趣的选择是:
std::istringstream tmp;
tmp << source.rdbuf();
std::string s( tmp.str() );
这可能非常快,如果实施已经做得很好
您正在使用的operator<<
,以及它如何在其中生成字符串
istringstream
。一些早期的实现(也许更多
然而,最近的那些人在这方面非常糟糕。
通常,使用std::string
的效果取决于具体方式
高效的实施是在增长一个字符串;实施
无法确定最初制作它的大小。你可能想要
将第一个使用相同代码的算法与std::vector<char>
进行比较
而不是std::string
,或者如果你可以做出很好的估计
最大尺寸,使用reserve
或类似:
std::string s( expectedSize, '\0' );
std::copy( std::istreambuf_iterator<char>( source ),
std::istreambuf_iterator<char>(),
s.begin() );
memcpy
无法读取文件,并且使用良好的编译器也不会
与使用std::copy
(具有相同的数据类型)一样快。
我倾向于使用上面的第二个解决方案,使用<<
rdbuf()
,但这部分是出于历史原因;我习惯了
在将STL添加到标准之前执行此操作(使用istrstream
)
图书馆。就此而言,您可能想要试验
istrstream
和预先分配的缓冲区(假设你可以找到一个
适当的缓冲区大小。)