http://insanecoding.blogspot.co.uk/2011/11/how-to-read-in-file-in-c.html回顾了在C ++中将整个文件读入字符串的多种方法。最快选项的关键代码如下所示:
std::string contents;
in.seekg(0, std::ios::end);
contents.resize(in.tellg());
in.seekg(0, std::ios::beg);
in.read(&contents[0], contents.size());
不幸的是,这不安全,因为它依赖于以特定方式实施的string
。例如,如果实现是共享字符串,那么修改&contents[0]
处的数据可能会影响正在读取的字符串。 (更一般地说,不能保证这不会破坏任意记忆 - 在实践中不太可能发生,但依靠它不是好习惯。)
C ++和STL旨在提供高效的C语言功能,因此可以预期上述版本的速度同样快,但保证安全。
在vector<T>
的情况下,有一些函数可用于访问原始数据,可用于有效地读取向量:
T* vector::data();
const T* vector::data() const;
其中第一个可用于有效地阅读vector<T>
。不幸的是,string
等效仅提供const
变体:
const char* string::data() const noexcept;
所以这不能用于有效地读取字符串。 (可能省略了non-const
变体以支持共享字符串实现。)
我还检查了字符串构造函数,但是那些接受char*
复制数据的构造函数 - 没有选项可以移动它。
是否有安全快捷的方法将文件的全部内容读入字符串?
值得注意的是,我想要阅读string
而不是vector<char>
,以便我可以使用istringstream
访问结果数据。对于vector<char>
,没有相同的内容。
答案 0 :(得分:2)
如果您确实想要避免复制,可以将文件粘贴到std::vector<char>
,然后滚动自己的std::basic_stringbuf
以从向量中提取数据。
然后,您可以声明std::istringstream
并使用std::basic_ios::rdbuf
将输入缓冲区替换为您自己的输入缓冲区。
需要注意的是,如果您选择致电istringstream::str
,则会调用std::basic_stringbuf::str
并需要副本。但是,听起来你似乎不需要这个功能,并且实际上可以将其删除。
这种方式是否能获得更好的性能需要实际测量。但至少你要避免在复制过程中必须有两个大的连续内存块。此外,如果您想要处理无法在连续内存中分配的真正巨大的文件,您可以使用std::deque
之类的东西作为底层结构。
还值得一提的是,如果您真的只是流式传输数据,那么通过首先将其读入字符串,您实际上是双缓冲。除非你还要求内存中的内容用于其他目的,否则std::ifstream
内的缓冲可能就足够了。如果你做啜饮文件,你可以通过关闭关闭来获得提升。
答案 1 :(得分:1)
我认为使用&string[0]
很好,它应该适用于广泛使用的标准库实现(即使它在技术上是UB)。
但是既然你提到要将数据放入istringstream
,这里有另一种选择:
new char[in.tellg()]
)stringstream
(不带领先'i') istringstream
无论如何都必须复制数据,因为据我所知,std::stringstream
内部并未存储std::string
,因此您可以离开{{ 1}}离开并直接将数据放入其中。
编辑:实际上,您也可以使用您提及的std::string
代替手动分配(或make_unique
)。