C++ 如何将文件内容读入istringstream?
为了提高从文件读取的性能,我尝试将一个大文件(数MB)的全部内容读取到内存中,然后使用istringstream访问信息 我的问题是,读取这些信息并将其“导入”到字符串流中的最佳方法是什么?这种方法的一个问题(见下文)是,在创建字符串流时,缓冲区会被复制,内存使用量会加倍C++ 如何将文件内容读入istringstream?,c++,optimization,memory,stream,stringstream,C++,Optimization,Memory,Stream,Stringstream,为了提高从文件读取的性能,我尝试将一个大文件(数MB)的全部内容读取到内存中,然后使用istringstream访问信息 我的问题是,读取这些信息并将其“导入”到字符串流中的最佳方法是什么?这种方法的一个问题(见下文)是,在创建字符串流时,缓冲区会被复制,内存使用量会加倍 #include <fstream> #include <sstream> using namespace std; int main() { ifstream is; is.open (s
#include <fstream>
#include <sstream>
using namespace std;
int main() {
ifstream is;
is.open (sFilename.c_str(), ios::binary );
// get length of file:
is.seekg (0, std::ios::end);
long length = is.tellg();
is.seekg (0, std::ios::beg);
// allocate memory:
char *buffer = new char [length];
// read data as a block:
is.read (buffer,length);
// create string stream of memory contents
// NOTE: this ends up copying the buffer!!!
istringstream iss( string( buffer ) );
// delete temporary buffer
delete [] buffer;
// close filestream
is.close();
/* ==================================
* Use iss to access data
*/
}
#包括
#包括
使用名称空间std;
int main(){
如果流是;
is.open(sFilename.c_str(),ios::binary);
//获取文件的长度:
is.seekg(0,std::ios::end);
长长度=is.tellg();
is.seekg(0,std::ios::beg);
//分配内存:
字符*缓冲区=新字符[长度];
//将数据作为块读取:
is.read(缓冲区、长度);
//创建内存内容的字符串流
//注意:这会复制缓冲区!!!
istringstream iss(字符串(缓冲区));
//删除临时缓冲区
删除[]缓冲区;
//关闭文件流
is.close();
/* ==================================
*使用iss访问数据
*/
}
std::ifstream
有一个方法rdbuf()
,该方法返回指向文件buf
的指针。然后,您可以将此filebuf
推送到您的stringstream
:
#include <fstream>
#include <sstream>
int main()
{
std::ifstream file( "myFile" );
if ( file )
{
std::stringstream buffer;
buffer << file.rdbuf();
file.close();
// operations on the buffer...
}
}
#包括
#包括
int main()
{
std::ifstream文件(“myFile”);
如果(文件)
{
std::stringstream缓冲区;
缓冲区对我来说,这似乎是过早的优化。在处理过程中要做多少工作。假设是一个现代化的桌面/服务器,而不是嵌入式系统,在初始化过程中复制几MB的数据是相当便宜的,尤其是与从磁盘读取文件相比。我会坚持你所拥有的,衡量t当系统完成时,由系统来决定潜在的性能提升是否值得。当然,如果内存紧张,这是在一个内部循环中,或者是一个经常被调用的程序(比如每秒调用一次),这会改变平衡。另一件需要记住的事情是,文件I/O总是最慢的操作。Luc Touraille的解决方案是正确的,但还有其他选择。一次将整个文件读入内存将比单独读取快得多。好的。我不是说这将比从文件
但这种方法只需创建一次缓冲区,在将数据读入缓冲区后,直接将其用作stringstream的源
注意:值得一提的是,std::ifstream是缓冲的。它以(相对较大的)块的形式从文件中读取数据。只有在需要更多数据时,才会对缓冲区执行流操作,并返回文件进行另一次读取。因此,在将所有数据吸入内存之前,请确认这是一个瓶颈
#include <fstream>
#include <sstream>
#include <vector>
int main()
{
std::ifstream file("Plop");
if (file)
{
/*
* Get the size of the file
*/
file.seekg(0,std::ios::end);
std::streampos length = file.tellg();
file.seekg(0,std::ios::beg);
/*
* Use a vector as the buffer.
* It is exception safe and will be tidied up correctly.
* This constructor creates a buffer of the correct length.
*
* Then read the whole file into the buffer.
*/
std::vector<char> buffer(length);
file.read(&buffer[0],length);
/*
* Create your string stream.
* Get the stringbuffer from the stream and set the vector as it source.
*/
std::stringstream localStream;
localStream.rdbuf()->pubsetbuf(&buffer[0],length);
/*
* Note the buffer is NOT copied, if it goes out of scope
* the stream will be reading from released memory.
*/
}
}
#包括
#包括
#包括
int main()
{
std::ifstream文件(“Plop”);
如果(文件)
{
/*
*获取文件的大小
*/
seekg(0,std::ios::end);
std::streampos length=file.tellg();
seekg(0,std::ios::beg);
/*
*使用向量作为缓冲区。
*它是异常安全的,将被正确地整理。
*此构造函数创建正确长度的缓冲区。
*
*然后将整个文件读入缓冲区。
*/
std::向量缓冲区(长度);
读取(&缓冲区[0],长度);
/*
*创建字符串流。
*从流中获取stringbuffer并将向量设置为它的源。
*/
std::stringstream localStream;
localStream.rdbuf()->pubsetbuf(&buffer[0],长度);
/*
*注意,如果缓冲区超出范围,则不会复制它
*流将从释放的内存中读取。
*/
}
}
Hi Luc,我同意你的建议…rdbuf的操作是一个不错的选择!但是你的解决方案不是也有同样的问题吗?你不创建同一缓冲区的两个副本吗,至少是暂时的吗?因为当operatorIt似乎正在删除我需要的新行字符时。isfile.close();
必要吗?@artm这不是强制性的,但最好在使用完文件句柄后立即关闭它们。如果没有对close
的显式调用,当file
被销毁时(在其作用域的末尾,因此在main
的末尾),文件就会被关闭。最好的方法可能是限制文件的范围。
@Martin York,你是如何了解这些细节的,当你遇到问题时,你是阅读还是研究,然后了解所有这些细节?非常感谢,bdw。@Gollum:不,这只是从两个方面获得的细节。1)一直使用流类。2)拥有实现了我自己的流类。数字(2)使您能够大量阅读流的工作原理,因为您希望流的工作方式与标准流的工作方式相同(这样您就可以对标准流重复使用STL库函数)。上面唯一不完整的一点是修改流缓冲区的工作方式。我不认为“因为char是一种未初始化的POD数据类型”这一点是正确的。构造函数实际上有两个参数,第二个参数是初始化元素的值。它默认为t()
或char()
在我们的例子中,表示0。因此所有元素都应该是0。-1,这个方法(basic_stringbuf::setbuf)是否定义了实现。@ybungalobill:是的。定义的实现不是“未定义”的。也许您应该改为搜索内存映射文件。您喜欢复制数据。1)复制到缓冲区。2)复制到匿名std::string。3)复制到iss。