2012-05-31 37 views
10

我想映射文件到內存,然後逐行解析 - istream我應該使用什麼?istream vs內存映射文件?

istream與在Windows上將文件映射到內存相同嗎?試圖找到將文件映射到內存的完整示例時遇到困難。

我已經看到人們鏈接msdn的內存映射文章,但如果有人可以推薦一個小的(〜15行?)例子,我將非常歡迎。

我一定在尋找錯誤的東西,但是當在google上搜索「C++內存映射的例子」時,我找不到一個包含迭代的例子。

這些都是最接近的結果(只是讓人們認識我已經看過):http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2044.html#ClassSharedMemoryObjectExample

http://msdn.microsoft.com/en-us/library/dd997372.aspx(沒有C++代碼)

http://beej.us/guide/bgipc/output/html/multipage/mmap.html(是爲Unix我相信,沒有窗戶)

+3

「*我試圖將文件映射到內存然後**然後**逐行解析*」。你能告訴我們爲什麼你想記憶地圖的文件?爲什麼不逐行解析(使用ifstream或fopen)就足夠了? –

+3

@Rob,純粹是出於性能原因。我在(錯誤?)印象之下,它更快地映射整個文件? – user997112

+2

@ user997112:這取決於你對數據做了什麼。如果您使用它來實現回溯的正確解析器,那麼內存映射文件無疑會更快;但如果你只是通過數據向前迭代(就像多個簡單的'std :: getline'調用一樣),我懷疑會有什麼明顯的差異。不過,除非虛擬地址空間不足(可能只是帶有GB +大小文件的32位代碼中的一個問題),否則肯定沒有使用內存映射文件的_harm_。 – ildjarn

回答

11

std::istream是一個抽象類型–你不能直接使用它。你應該從它派生一個自定義陣列支持streambuf

#include <cstddef> 
#include <string> 
#include <streambuf> 
#include <istream> 

template<typename CharT, typename TraitsT = std::char_traits<CharT>> 
struct basic_membuf : std::basic_streambuf<CharT, TraitsT> { 
    basic_membuf(CharT const* const buf, std::size_t const size) { 
     CharT* const p = const_cast<CharT*>(buf); 
     this->setg(p, p, p + size); 
    } 

    //... 
}; 

template<typename CharT, typename TraitsT = std::char_traits<CharT>> 
struct basic_imemstream 
: virtual basic_membuf<CharT, TraitsT>, std::basic_istream<CharT, TraitsT> { 
    basic_imemstream(CharT const* const buf, std::size_t const size) 
    : basic_membuf(buf, size), 
     std::basic_istream(static_cast<std::basic_streambuf<CharT, TraitsT>*>(this)) 
    { } 

    //... 
}; 

using imemstream = basic_imemstream<char>; 

char const* const mmaped_data = /*...*/; 
std::size_t const mmap_size = /*...*/; 
imemstream s(mmaped_data, mmap_size); 
// s now uses the memory mapped data as its underlying buffer. 

至於內存映射本身,我建議使用Boost.Interprocess爲了這個目的:

#include <cstddef> 
#include <string> 
#include <boost/interprocess/file_mapping.hpp> 
#include <boost/interprocess/mapped_region.hpp> 

namespace bip = boost::interprocess; 

//... 

std::string filename = /*...*/; 
bip::file_mapping mapping(filename.c_str(), bip::read_only); 
bip::mapped_region mapped_rgn(mapping, bip::read_only); 
char const* const mmaped_data = static_cast<char*>(mapped_rgn.get_address()); 
std::size_t const mmap_size = mapped_rgn.get_size(); 

代碼imemstream取自this answer通過Dietmar Kühl

+2

來自mmaped_data的輸入來自哪裏?我們需要參考我認爲的文件? – user997112

+1

@ user997112:這取決於你在哪個平臺上 - 標準C++不提供內存映射文件。在* nix上,有'mmap';在Windows上,有'CreateFileMapping'。就個人而言,我使用[Boost.Interprocess](http://www.boost.org/libs/interprocess/)的內存映射文件,因爲它們是跨平臺的;我將以此爲例進行編輯。 – ildjarn

+0

謝謝,非常感謝 – user997112

1

istream與將文件映射到Windows上的內存相同嗎?

不完全是。它們在相同的意義上並不相同,「流」不是「文件」。

將文件視爲存儲的序列,並將其作爲存儲序列在從存儲區移動到接收變量時流動的「通道」(stream_buffer)的接口。

將存儲器映射文件視爲「文件」,該文件存儲在處理單元之外 - 存儲在內存中。它具有作爲文件的原始內存緩衝區可見的優點。如果您想將其作爲流讀取,最簡單的方法可能是使用具有該原始緩衝區作爲讀取位置的istringstream。

+0

說實話,我寧願一次讀取整個文件,而不是流 – user997112

+0

@ user997112:這取決於你的內容。如果文件是文本,而你要讀取數字,則必須以某種方式解析它。 std :: istream(和派生)就是這個解析器。 –