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

时间:2015-07-03 18:46:04

标签: c++ arrays c++11 vector binaryfiles

我有非常简单但很大的载体:

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二进制文件后它很容易获得? 顺便说一句,我不坚持使用向量,我可以使用数组或任何数据类型更适合我的情况......

4 个答案:

答案 0 :(得分:2)

读取和写入向量的整个数据部分的技巧是在写入之前获取数据块的大小,然后在读取数据块之前获取数据块的大小。但是当然,你你读它时不知道大小,所以大小也需要在文件中。这允许您为矢量分配那么多空间,然后读取那么多数据。

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

#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)

  1. 您不能简单地在单个命令中写出向量列表。虽然向量可以保证它们将数据存储在连续的存储空间中,但不同向量的数据不会是连续的。
  2. 如果你以你正在做的方式写出向量,就不可能正确地读回来,因为你不知道向量有多少元素。
  3. 鉴于一个向量,将其写出并读入的正确方法是这样的:

    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();)。

答案 2 :(得分:1)

你的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]));

答案 3 :(得分:1)

  

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

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

请注意:

  

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

错了。 $client->post('URI', ['form_params' => ['some' => 'params']]); 实际上是堆栈上向量的大小,而sizeof(A)返回指向上的数据的指针。 要获取数据大小,请使用&A[0]并获取指向数据的指针A.size() * sizeof(A[0])

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

如果你的代码看起来像这样

A.data()

请务必在上一行之前致电:

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

或启动A大小,如下:

A.resize(sizeToRead);