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

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

本文关键字:二进制文件 一个 几个 何一次 c++ 简单      更新时间:2023-10-16

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

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二进制文件后随时使用了吗?顺便说一句,我并不坚持使用向量,我可以使用数组或任何更适合我的数据类型。。。

读取和写入矢量的整个数据段的诀窍是在写入之前先获取数据块的大小,然后在读取之前先获取该数据块的尺寸。但当然,读取时您不知道大小,因此大小也需要在文件中。这允许您为向量分配那么多空间,然后读取那么多数据。

以下是一种可能的实现方式。我走了捷径。你的文件头可能应该有一个可以检查的标识符,这样你就知道你正在读取一个声称正确遵循你布局的文件。你真的,真的需要检查文件打开和读写是否有效。我没有为我的运算符==((编写测试,我用它来测试加载/保存对(尽管我在调试器中检查过一次值(。

#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. 你不能简单地在一个命令中写出一个向量列表。尽管矢量保证它们将数据存储在连续的存储空间中,但不同矢量的数据不会是连续的
  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 ...
};

然后以下读/写命令将起作用:

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 ...
};

这两种方法都需要对每个数组的大小设置一个严格的上限,如果你想让它们看起来是动态大小的,你还需要安排一些特定的值来用作元素不存在的标记(一种方法是#include <limit>,然后有const int EMPTY = numeric_limits<int>::min();(。

YOur 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]));

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

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

注意:

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

是错误的。sizeof(A)实际上是堆栈上向量的大小,而&A[0]返回指向中数据的指针。使用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);
相关文章: