2008-09-25 56 views
30

为了提高从文件读取数据的性能,我试图将一个大(几MB)文件的全部内容读入内存,然后使用istringstream来访问这些信息。如何将文件内容读入istringstream?

我的问题是,这是读取此信息并将其“导入”到字符串流中的最佳方式?这种方法的一个问题(见下文)是,当创建字符串流时,缓冲区被复制,内存使用量加倍。

#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 
    */ 

} 
+2

您喜欢复制数据。 1)复制到缓冲区。 2)复制到匿名的std :: string。 3)复制到iss。 – 2008-09-26 10:34:43

+0

也许你应该搜索内存映射文件。 – 2008-09-25 09:50:28

回答

32

std::ifstream有一个方法rdbuf(),它返回一个指向filebuf。然后,您可以“推”这个filebuf到您的stringstream

int main() 
{ 
    std::ifstream file("myFile"); 

    if (file) 
    { 
     std::stringstream buffer; 

     buffer << file.rdbuf(); 

     file.close(); 

     // operations on the buffer... 
    } 
} 

编辑:正如评论马丁纽约的话,这可能不是因为stringstreamoperator<<将字符读filebuf字符最快的解决方案。您可能想要检查他的答案,他像以前一样使用ifstreamread方法,然后将stringstream缓冲区设置为指向先前分配的内存。

+0

嗨,吕克, 我同意你的建议...... rdbuf的操作是要走的路!但doens't你的解决方案有同样的问题?你是否至少暂时创建2个相同缓冲区的副本? – 2008-09-25 10:18:57

1

这对我来说似乎是不成熟的优化。在处理中正在做多少工作。假设一个现代化的桌面/服务器,而不是嵌入式系统,在初始化过程中复制几MB数据相当便宜,尤其是与首先从磁盘读取文件相比。我会坚持你所拥有的,在完成时测量系统,并决定潜在的性能收益是否值得。当然,如果内存紧张,这是一个内部循环,或者经常被调用的程序(如每秒一次),这会改变平衡。

0

要记住的另一件事是文件I/O总是最慢的操作。 Luc Touraille的解决方案是正确的,但还有其他选择。一次将整个文件读入内存将比单独读取快得多。

40

好的。我并不是说这会比从文件中读取更快

但是,这是一种方法,您可以在数据读入缓冲区之后创建缓冲区,直接将其用作stringstream的源。

N.B.值得一提的是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. 
     */ 
    } 
} 
相关问题