一次将文件读入矢量

Reading a file into a vector all at once

本文关键字:文件 一次      更新时间:2023-10-16

这是读取std::vector的好主意吗,还是这里有一些问题:

using namespace std;
ifstream file("blah.dat", ios::binary);
vector<T> v(N);
file.read(static_cast<char*>(v.data()), N * sizeof(T));

vector标准允许我这样做来填充矢量吗?为了简化起见,让我们假设T是一个普通的旧数据类型。

如果T是可复制的,那么这里没有未定义的行为,POD当然是。保证vector<T>::data返回指向vector<T>::size Ts的连续数组的指针,并且保证普通可复制类型T的对象表示是sizeof(T)字节的连续序列(可能包括内部填充)。

如果存储在该空间中的字节不是有效的T对象表示,则在访问它们时可能会得到未定义的行为。究竟哪个字节序列构成有效的CCD_ 10对象表示是一个灰色区域;至少,您应该能够将一个普通可复制类型的对象的底层字节可移植地写入文件,并成功地将它们读回同一类型对象的底层比特中。

为了偏执狂,我可能会说:

static_assert(std::is_trivially_copyable<T>(),
              "NO NO NO - T MUST BE TRIVIALLY COPYABLE!");

在CCD_ 11之前用于将来的校对。

看起来您将受益于内存映射文件。Boost提供了两种实现,因此您不必直接使用mmap()

使用boost.iostreams:

#include <boost/iostreams/device/mapped_file.hpp>
boost::iostreams::mapped_file_source file("blah.dat");
std::size_t size = file.size() / sizeof(T);
const T * ptr = reinterpret_cast<const T*>(file.data());
for (std::size_t i=0; i<size; ++i)
    std::cout << ptr[i] << std::endl;

您也可以使用boost.interprocess,但本质上相同的功能需要更多的代码。

主要优点是您不分配任何内存来访问文件,它将在访问数据时按需加载。数据本身将存在于缓存/缓冲的页面中,因此不会占用任何内存(如果系统需要其他内存,则会丢弃这些内存)。

你不应该这样做,事实上你应该做的(因为最初的C++)是这个

std::ifstream file("foo.txt");
file >> std::noskipws;            // use this line so that whitespace won't be skipped
std::vector<char> buffer(std::istream_iterator<char>(file),
                         std::istream_iterator<char>());

你不应该按照自己的方式来做的原因是,对象存在于文件中是没有意义的(至少在C++中是这样)。文件只包含字符,然后由operator>>格式化这些字符以创建对象。该标准允许编译器对对象做一些非常奇怪的事情(尤其是在启用RTTI时),这使得将对象"保存"到文件变得毫无用处。您最好只为它创建自己的序列化格式。