c ++,如何一次将几个简单的向量写入二进制文件

c++, how to write several simple vectors to a binary file in one shot

我有非常简单但巨大的向量:

struct Vectors //of the same types and the same sizes
{
    vector<int> A;
    vector<int> B;
    vector<int> C;
    vector<int> D;
    vector<int> E;
    vector<int> F;
}

并想一次性将它们写入二进制文件。

到目前为止,我在以下帮助下成功地将单个向量写入和读取到二进制文件:file.write(reinterpret_cast<const char*>(&A[0]), sizeof(A));file.read(reinterpret_cast<char*>(&A[0]), sizeof(binaryfile));

我依次对这6个向量做了同样的事情,但是当我尝试读取二进制文件时,出现错误:vector subscript out of range

问题可能出在自动填充上吗?以及如何克服它? 是否可以一次写入然后读取整个向量结构?以便在我内存 mmap 二进制文件后随时可用? 顺便说一句,我不坚持使用向量,我可以使用数组或任何更适合我的数据类型...

你的sizeof()绝对错误

对于类型为 T 的向量(在您的情况下为 int)作为大小,您应该 v.size()*sizeof(T)

类似

file.write(reinterpret_cast<const char*>(&A[0]), A.size()*sizeof(A[0]));

更新

如果您使用的是 C++11,那么您可以直接访问底层存储 A.data(),因此

file.write(reinterpret_cast<const char*>(A.data()), A.size()*sizeof(A[0]));

I want to write them to a binary file in one shot.

你不能做这样的事。 为了使用单个函数批量写入所有向量,向量中分配的所有数据必须是连续的(你不能保证)。您可以一个一个地保存向量,这可能是最好和最简单的解决方案。

注意:

file.write(reinterpret_cast(&A[0]), sizeof(A));

错了。 sizeof(A) 实际上是 堆栈上向量的大小 ,而 &A[0] returns 是指向它在 堆上的数据的指针。 要获取数据的大小,请使用 A.size() * sizeof(A[0]) 并获取指向数据的指针,请使用 A.data()

您在读取时遇到错误,这是因为您没有在向量上分配足够的内存。向量的大小为 0,索引 0 不存在,因此 &A[0] 抛出异常。使用函数 A.data() 可以解决这个问题,但是您仍然需要分配足够的内存才能填充向量。

如果您的代码如下所示

size_t sizeToRead; // Retrieved from somewhere 
file.read(reinterpret_cast<char*>(A.data()), sizeToRead);

确保您在上述行之前致电:

A.resize(sizeToRead);

或者用尺寸启动 A,像这样:

vector<int> A(sizeToRead);

读取和写入向量的整个数据部分的技巧是在写入之前获取数据块的大小,然后在读取之前获取数据块的大小it.But当然,您在阅读时并不知道大小,因此大小也需要在文件中。这允许您为向量分配那么多 space,然后读取那么多数据。

这是一种可能的实现方式。我走了捷径。您的文件头可能应该有一个可以检查的标识符,这样您就知道您正在阅读一个声称正确遵循您的布局的文件。您真的非常需要检查文件是否打开以及 reads/writes 是否有效。而且我没有为我的 operator==() 编写测试,我用它来测试 load/save 对(尽管我确实在调试器中检查过一次值)。

#include "stdafx.h"
#include <iostream>
#include <vector>
#include <fstream>

struct Vectors {
    std::vector<int> A, B, C, D, E, F;
    bool save(const char * filename);
    bool load(const char * filename);
    bool operator == (const Vectors &rhs);
};

void initialize_dummy_ints(std::vector<int> &v, int size){
    v.resize(size);
    for (int n = 0; n < size; ++n)
        v[n] = n + 1;
}

bool Vectors::save(const char * filename){
    std::ofstream out(filename, std::ios::binary);
    int a=A.size(), b=B.size(), c=C.size(), d=D.size(), e=E.size(), f=F.size();
    out.write(reinterpret_cast<const char*>(&a), sizeof(a));
    out.write(reinterpret_cast<const char*>(&b), sizeof(b));
    out.write(reinterpret_cast<const char*>(&c), sizeof(c));
    out.write(reinterpret_cast<const char*>(&d), sizeof(d));
    out.write(reinterpret_cast<const char*>(&e), sizeof(e));
    out.write(reinterpret_cast<const char*>(&f), sizeof(f));

    out.write(reinterpret_cast<const char*>(&A[0]), sizeof(int)*A.size());
    out.write(reinterpret_cast<const char*>(&B[0]), sizeof(int)*B.size());
    out.write(reinterpret_cast<const char*>(&C[0]), sizeof(int)*C.size());
    out.write(reinterpret_cast<const char*>(&D[0]), sizeof(int)*D.size());
    out.write(reinterpret_cast<const char*>(&E[0]), sizeof(int)*E.size());
    out.write(reinterpret_cast<const char*>(&F[0]), sizeof(int)*F.size());

    // always check to see if the file opened, and if writes succeeded.  
    // I am being lazy here so I can focus on the actual question
    return true;
}

bool Vectors::load(const char *filename){
    std::ifstream in(filename, std::ios::binary);
    int a, b, c, d, e, f;
    in.read(reinterpret_cast<char*>(&a), sizeof(a));
    in.read(reinterpret_cast<char*>(&b), sizeof(b));
    in.read(reinterpret_cast<char*>(&c), sizeof(c));
    in.read(reinterpret_cast<char*>(&d), sizeof(d));
    in.read(reinterpret_cast<char*>(&e), sizeof(e));
    in.read(reinterpret_cast<char*>(&f), sizeof(f));
    A.resize(a); B.resize(b); C.resize(c); D.resize(d); E.resize(e); F.resize(f);

    in.read(reinterpret_cast<char*>(&A[0]), sizeof(int)*A.size());
    in.read(reinterpret_cast<char*>(&B[0]), sizeof(int)*B.size());
    in.read(reinterpret_cast<char*>(&C[0]), sizeof(int)*C.size());
    in.read(reinterpret_cast<char*>(&D[0]), sizeof(int)*D.size());
    in.read(reinterpret_cast<char*>(&E[0]), sizeof(int)*E.size());
    in.read(reinterpret_cast<char*>(&F[0]), sizeof(int)*F.size());

    // always check to see if the file opened, and if writes succeeded.  
    // I am being lazy here so I can focus on the actual question
    return true;
}

bool matches(const std::vector<int> &l, const std::vector<int> &r){
    if (l.size() != r.size())
        return false;
    for (size_t x = 0; x < l.size(); ++x)
        if (l[x] != r[x])
            return false;
    return true;
}

bool Vectors::operator==(const Vectors &rhs){
    return matches(A, rhs.A) && matches(B, rhs.B) && matches(C, rhs.C) && matches(D, rhs.D) && matches(E, rhs.E) && matches(F, rhs.F);
}

int main()
{
    // setup
    Vectors starting_values;
    initialize_dummy_ints(starting_values.A, 10);
    initialize_dummy_ints(starting_values.B, 12);
    initialize_dummy_ints(starting_values.C, 14);
    initialize_dummy_ints(starting_values.D, 10);
    initialize_dummy_ints(starting_values.E, 5);
    initialize_dummy_ints(starting_values.F, 2);

    // write to file
    starting_values.save("data.bin");

    // read back in to memory
    Vectors loaded_values;
    loaded_values.load("data.bin");

    // compare
    if (loaded_values == starting_values)
        std::cout << "success";
    else
        std::cout << "failure";

    return 0;
}
  1. 您不能简单地在单个命令中写出向量列表。虽然vector保证它们的数据存储在连续的存储中space,但是不同vector的数据不会是连续的
  2. 如果你按照你现在的方式写出向量,就不可能正确读回它,因为你不知道向量有多少元素。

给定一个向量,写出和读入的正确方法是这样的:

void writeVector(ostream& file, const vector<int>& A) {
    size_t count = A.size();
    file.write(reinterpret_cast<const char*>(&size), sizeof(size));
    file.write(reinterpret_cast<const char*>(A.data()), sizeof(A[0]) * count);
}

void readVector(istream& file, vector<int>& A) {
    size_t size = 0;
    file.read(reinterpret_cast<char*>(*size), sizeof(size));
    A.resize(size); // Make sure the vector has space for what you're about to read in!
    file.read(reinterpret_cast<char*>(A.data()), sizeof(A[0]) * count);
}

我想不出有什么方法可以像您想要的那样一次写出所有向量。我怀疑这是不可能的。尽管使用 vector<vector<int>> 而不是 struct Vectors 可能会有所帮助,因为这样您就可以简单地 运行 像上面这样的循环代码:

void writeVectors(ostream& file, const vector<vector<int>>& stuff) {
    size_t count = stuff.size();
    file.write(reinterpret_cast<const char*>(&size), sizeof(size));
    for(const vector<int>& v : stuff) {
        writeVector(file, v);
    }
}

void readVectors(istream& file, vector<vector<int>>& stuff) {
    size_t count = 0;
    file.read(reinterpret_cast<char*>(*size), sizeof(size));
    A.resize(size); // Make sure the vector has space for what you're about to read in!
    for(const vector<int>& v : stuff) {
        readVector(file, v);
    }
}

现在,如果您想要的是可以轻松一次性写出的东西,那么您必须选择静态尺寸的东西。基本上,这意味着您需要使用数组。如果你有这样的结构:

struct Vectors {
    int A[50];
    int B[50];
    int C[50];
    // ... etc ...
};

然后以下 read/write 命令将起作用:

file.write(reinterpret_cast<const char*>(&A), sizeof(A));
file.read(reinterpret_cast<char*>(&A), sizeof(A));

我认为不太可能会有填充,但不能保证。

如果 Vectors 定义如下:

#include <array>

struct Vectors {
    array<int,50> A;
    array<int,50> B;
    array<int,50> C;
    // ... etc ...
};

这两种方式都要求您为每个数组的大小设置一个硬性上限,如果您希望它们看起来[=44​​=]动态调整大小,您还需要安排一些特定值用作元素不存在的标记(一种方法是 #include <limit> 然后 const int EMPTY = numeric_limits<int>::min();)。