istream vs内存映射文件?

时间:2012-05-31 19:07:25

标签: c++

我正在尝试将文件映射到内存然后逐行解析 - istream我应该使用什么?

istream是否与在Windows上将文件映射到内存相同?我在尝试找到将文件映射到内存的完整示例时遇到了困难。

我见过人们链接来自MSDN的内存映射文章,但如果有人可以推荐一个小的(~15行?)示例,我会非常感激。

我一定是在寻找错误的东西,但在Google上搜索“C ++内存映射示例”时,我找不到包含迭代的示例。

这些是最接近的结果(只是让人们意识到我看了):

3 个答案:

答案 0 :(得分:12)

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

答案 1 :(得分:1)

  

istream是否与在Windows上将文件映射到内存相同?

不完全是。它们在同一意义上不同,“流”不是“文件”。

将文件视为存储序列,并将流视为当从存储移动到接收变量时序列流动的“通道”(stream_buffer)的接口。

将内存映射文件视为“文件”,它仍然存储在处理单元之外 - 在内存中同步存储。它具有作为文件的原始内存缓冲区可见的优点。如果您想将其作为流读取,最简单的方法可能是使用具有该原始缓冲区作为读取位置的istringstream。

答案 2 :(得分:0)

抽象地讲,使用内存映射文件或先将其读取到内存不会加快顺序读取文件的速度。如果顺序读取文件不可行,则内存映射文件有意义。像在其他答案中一样预先缓存文件,或者只是将文件复制到大字符串,然后可以通过其他方式处理-再次-仅在顺序读取一次文件不可行并且您有RAM用于以下目的时才有意义它。这是因为操作最慢的部分实际上是从磁盘上获取数据。无论是将文件复制到RAM还是让操作系统在访问数据之前映射数据,还是让std :: iostream逐行读取数据并让其从文件中缓存,都必须这样做足以使此工作顺利进行。

实际上,通过对缓冲区范围进行浅表复制,可以潜在地消除从ram到映射或缓存版本的ram的某些复制。仍然不会有太大变化,因为这是RAM-> RAM,因此与disk-> RAM相比可以忽略不计。

因此,在您这样的情况下,最好的建议是不要太担心,而只需使用std :: iostream。

[此答案出于存档目的,因为正确的答案隐藏在评论中]