13

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

istream 与将文件映射到 Windows 上的内存相同吗?我很难找到将文件映射到内存的完整示例。

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

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

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

4

3 回答 3

14

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取自Dietmar Kühl这个答案

于 2012-05-31T19:11:55.627 回答
1

istream 与将文件映射到 Windows 上的内存相同吗?

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

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

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

于 2012-05-31T19:22:07.110 回答
1

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

在实践中,您可以通过制作缓冲区范围的浅拷贝来潜在地消除使用映射或缓存版本从 ram 到 ram 的一些复制。这仍然不会有太大变化,因为这是 RAM->RAM,因此与磁盘->RAM 相比可以忽略不计。

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

[此答案用于存档目的,因为正确答案埋在评论中]

于 2019-11-02T20:10:05.053 回答