2011-06-09 100 views
3

你也可以爲你的文件流指定一個緩衝區:std :: fstream與多個緩衝區?

char buf[BUFFER_SIZE]; 

std::ofstream file("file", std::ios_base::binary | std::ios_base::out); 
if (file.is_open()) 
{ 
    file.rdbuf()->pubsetbuf(buf, BUFFER_SIZE); 
    file << "abcd"; 
} 

我想現在要做的,不僅僅是一個緩衝區使用更多:

char* buf[] = { new char[BUFFER_SIZE], new char[BUFFER_SIZE], new char[BUFFER_SIZE], }; 

是否有可能,而無需創建一個自定義派生std :: streambuf?

編輯: 我想我需要解釋我想做更詳細的。請考慮以下情況: - 我想要讀取的文件不適合內存 - 文件被某種二進制跳轉搜索訪問

因此,如果將文件拆分爲邏輯頁面的特定大小,然後我想提供多個緩衝區來表示特定的頁面。這會在讀取文件位置並且相關頁面已經在緩衝區中時提高性能。

+1

對於多個緩衝區,你會期望什麼語義? – 2011-06-09 14:09:19

+0

1)我想指定一個巨大的緩衝區,不想強制系統分配一個這樣的大小。 2)我有多個應用程序經常隨機訪問的大文件。所以,我想讀取和寫入緩衝區以提高性能。 – 0xbadf00d 2011-06-09 14:43:32

回答

1

我會看看boost :: iostreams :: mapped_file,但我認爲我的要求更簡單。我創建了一個從basic_filebuf派生的自定義類。

template<typename char_type> 
class basic_filemultibuf : public std::basic_filebuf<char_type/*, std::char_traits<char_type>*/> 
{ 
private: 
    char_type**  m_buffers; 
    std::ptrdiff_t m_buffer_count, 
        m_curent_buffer; 
    std::streamsize m_buffer_size; 

protected: 
    virtual int_type overflow(int_type meta = traits_type::eof()) 
    { 
     if (this->m_buffer_count > 0) 
     { 
      if (this->m_curent_buffer == this->m_buffer_count) 
       this->m_curent_buffer = 0; 
      this->basic_filebuf::setbuf(this->m_buffers[this->m_curent_buffer++], this->m_buffer_size); 
     } 

     return this->basic_filebuf::overflow(meta); 
    } 

public: 
    basic_filemultibuf(basic_filebuf const& other) 
     : basic_filebuf(other), 
      m_buffers(NULL), 
      m_buffer_count(0), 
      m_curent_buffer(-1), 
      m_buffer_size(0) 
    { 
    } 

    basic_filemultibuf(basic_filemultibuf const& other) 
     : basic_filebuf(other), 
      m_buffers(other.m_buffers), 
      m_buffer_count(other.m_buffer_count), 
      m_curent_buffer(other.m_curent_buffer), 
      m_buffer_size(other.m_buffer_size) 
    { 
    } 

    basic_filemultibuf(FILE* f = NULL) 
     : basic_filemultibuf(basic_filebuf(f)) 
    { 
    } 

    basic_filemultibuf* pubsetbuf(char** buffers, std::ptrdiff_t buffer_count, std::streamsize buffer_size) 
    { 
     if ((this->m_buffers = buffers) != NULL) 
     { 
      this->m_buffer_count = buffer_count; 
      this->m_buffer_size = buffer_size; 
      this->m_curent_buffer = 0; 
     } 
     else 
     { 
      this->m_buffer_count = 0; 
      this->m_buffer_size = 0; 
      this->m_curent_buffer = -1; 
     } 

     this->basic_filebuf::setbuf(NULL, 0); 
     return this; 
    } 
}; 

用法示例:

typedef basic_filemultibuf<char> filemultibuf; 

std::fstream file("file", std::ios_base::binary | std::ios_base::in | std::ios_base::out); 

char** buffers = new char*[2]; 
for (int i = 0; i < n; ++i) 
    buffers[i] = new char[4096]; 

filemultibuf multibuf(*file.rdbuf()); 
multibuf.pubsetbuf(buffers, 2, 4096); 
file.set_rdbuf(&multibuf); 

// 
// do awesome stuff with file ... 
// 

for (int i = 0; i < n; ++i) 
    delete[] buffers[i]; 

這幾乎是它。我真正想要做的唯一事情就是爲其他流緩衝區提供此功能,因爲多個緩衝區的使用不應僅限於filebuf。但是在我看來,如果不重寫文件特定的功能是不可能的。

您對此有何看法?

1

我從評論中收集到你想要做的一種scatter-gather I/O。我很肯定在C++標準I/O流庫中不支持這個功能,所以你必須推出自己的。

如果要高效地執行此操作,可以使用操作系統支持進行分散收集。例如,POSIX/Unix-like系統爲此目的具有writev

+0

感謝您的回答。我已經更新了我的初始文章,並更詳細地描述了我的要求。 – 0xbadf00d 2011-06-10 17:08:52

1

沒有什麼像標準提供的。但是,根據您的平臺,可以使用提供相同功能的內存映射文件。 Windows和Linux都提供它們。

+1

這似乎符合OP的要求+1。不要忘記[Boost中的可移植內存映射文件](http://www.boost.org/doc/libs/release/libs/iostreams/doc/classes/mapped_file.html)。 – 2011-06-10 20:30:52

+0

我會看看,但我已經實現了一個相當不錯的解決方案(從我的角度來看)。如果你分享你的想法,我將不勝感激。 – 0xbadf00d 2011-06-11 09:56:10