2008-09-25 54 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. 
     */ 
    } 
} 
相關問題