如何创建从二进制文件读取数据的结构的动态数组

时间:2018-09-19 15:16:10

标签: visual-c++ struct binaryfiles

我有一个struct,它描述了存储在二进制文件中的数据对象。该结构看起来像:

struct Sum_str {
public:
    char    FINISH_T[24]; // U4
    char    DISP_COD; // C1
    char    USR_DESC[128]; // Cn
    char    EXC_DESC[128]; // Cn
};

这是通过读取二进制文件加载的,并且文件中数据对象的数量可能有所不同。当我通过structconst声明为设置限制时,一切正常。不幸的是,二进制文件可以具有比声明的更少或更多的数据。

如何根据二进制文件中存储的对象数量,根据需要动态增长数组?

2 个答案:

答案 0 :(得分:0)

如果数组的大小可以大于给定的最大值(24、128、128),则说明您使用的容器不是正确的。如果您需要容器的大小是动态的,请使用向量代替数组

struct Sum_str {
public:
    std::vector<char>    FINISH_T; // U4
    char                 DISP_COD; // C1
    std::vector<char>    USR_DESC; // Cn
    std::vector<char>    EXC_DESC; // Cn
};

如果限于阵列,则仅按其各自的长度填充阵列。请记住,在数据的末尾放置空终止符,以免在打印内容时意外读取char数组。另外,对数组大小使用#define代替魔术数字。

如果不确定需要多少Sum_str结构,则应使用适合您要求的容器。您的要求需要一个可以改变大小的容器,因此您应该使用vector

std::vector<Sum_str> my_container;

答案 1 :(得分:0)

您没有指定二进制文件的实际格式,因此我将假定它包含您提供的结构数组。

因此您的基本算法将如下所示:

  • std::vector一样创建结构的std:vector <Sum_str > myVect;
  • 接下来从二进制文件的正确位置开始,我假设偏移量为0,读取了一条二进制记录,这意味着将结构作为二进制对象读取
  • 将其放入向量中,如myVect.push_back(obj);
  • 继续读取对象并将其放入向量中,直到达到我认为是文件结尾的适当终点为止

主要和从属假设是二进制文件包含等于结构数组Sum_str的二进制映像的零个或多个。这很重要的原因是您要确保:

  • 文件中Sum_str对象的大小与内存中Sum_str对象的大小
  • 文件中Sum_str对象的成员的布局和偏移与内存中Sum_str对象的成员的布局和偏移

如果二进制文件仅包含结构数据数组,则您可能需要估计文件中包含的结构数,并以近似于估计的初始容量创建std::vector。请参阅Initial capacity of vector in C++Using C++ filestreams (fstream), how can you determine the size of a file?,其中提供了一种计算文件大小的方法。尽管在Windows和Linux上的二进制文件看起来已经足够接近了,但是tellg()这种获取文件大小的方法并不可靠。

请参见Reading and writing binary fileHow to read a binary file into a vector of unsigned chars以及c++ Read/Write class from/to binary fileC++ binary files and iterators: getting away with a 1:1 using ifstreambuf_iterator?

首次剪切-使用较早版本的C ++进行的简单演示

我在哪里没有C ++ 11/17,所以这里是一个使用较旧的C ++编译器的版本,直到我可以使用较新的版本并可以进行一些研究为止。

#include <iostream>
#include <fstream>
#include <vector>

struct Person
{
  char name[50];
  int age;
  char phone[24];
};

int mainx()
{
  Person me = {"Robert", 28, "364-2534"};
  Person book[30];
  int x = 123;
  double fx = 34.54;

  // put in some data for our output to show that it works.
  for (int i = 0; i < 30; i++) {
      book[i] = me;
      book[i].age = i *10 + 5;  // modify the age so we can see it changed.
  }
  std::ofstream outfile;
  outfile.open("junk.dat", std::ios::binary | std::ios::out);
  outfile.write((char *)&x, sizeof(int)); // sizeof can take a type
  outfile.write((char *)&fx, sizeof(fx)); // or it can take a variable name
  outfile.write((char *)&me, sizeof(me));
  outfile.write((char *)book, 30*sizeof(Person));
  outfile.close();

  return 0;
}

int mainy()
{
  Person me = {0};
  std::vector<Person>book;
  int x = 0;
  double fx = 0;
  std::ifstream infile;
  infile.open("junk.dat", std::ios::binary | std::ios::in);
  infile.read((char *)&x, sizeof(int)); // sizeof can take a type
  infile.read((char *)&fx, sizeof(fx)); // or it can take a variable name
  infile.read((char *)&me, sizeof(me));
  for (int i = 0; i < 30; i++) {
      Person buff;
      infile.read((char *)&buff, sizeof(Person));
      book.push_back(buff);
  }

  infile.close();

  std::cout << "x = " << x << std::endl;
  std::cout << "fx = " << fx << std::endl;

  std::cout << "Person me = " << me.name << ", age " << me.age << ", phone " << me.phone << std::endl;

  for (int i = 0; i < 30; i++) {
    std::cout << "Person book = " << i << "  " << book[i].name << ", age " << book[i].age << ", phone " << book[i].phone << std::endl;
  }
  return 0;
}

int main ()
{
    mainx();
    mainy();
    return 0;
}

附录-使用迭代器进行演示

这是上面修改为使用迭代器的第二个示例。这不是我的专业领域,但是我在控制台应用程序中使用Visual Studio 2017进行的测试表明它可以正常工作。

另请参阅istream_iterator Class

#include <iterator>
#include <iostream>
#include <fstream>
#include <vector>

struct Person
{
    char name[50];
    int age;
    char phone[24];

    friend std::ostream& operator<<(std::ostream& os, const Person& dt);
    friend std::istream& operator<<(std::istream& os, const Person& dt);
};

std::ostream& operator<<(std::ostream& os, const Person& dt)
{
    os.write((char *)&dt, sizeof(Person));
    return os;
}

std::istream& operator>>(std::istream& os, const Person& dt)
{
    os.read((char *)&dt, sizeof(Person));
    return os;
}

// construct a binary file that contains various objects.
// in the following routine we will read back out from
// the binary file the objects we wrote into it.
int mainx()
{
    Person me = { "Robert", 28, "364-2534" };
    std::vector<Person> book;
    int x = 123;
    double fx = 34.54;

    // put in some data for our output to show that it works.
    for (int i = 0; i < 30; i++) {
        Person x = me;
        x.age = i * 10 + 5;  // modify the age so we can see it changed.

        book.push_back (x);
    }

    // construct out output file with the various objects
    // we want to save. when we read from this file
    // we will want to use the same types of variables
    // in the same order since there is no meta data
    // in this file to indicate object types or object boundaries.
    std::ofstream outfile("junk.dat", std::ios::binary | std::ios::out);
    outfile << x;
    outfile << fx;
    outfile << me;

    // write out the vector of Person objects.
    for (auto x : book) outfile << x;

    outfile.close();

    return 0;
}

// following routine opens the persistent store and reads
// back in the objects that were saved. we need to do
// the reading in the same order they were written.
int mainy()
{
    Person me = { 0 };
    int x = 0;
    double fx = 0;
    std::ifstream infile("junk.dat", std::ios::binary | std::ios::in);
    infile >> x;
    infile >> fx;
    infile >> me;

    // istream_iterator from stream infile
    std::istream_iterator<Person> is(infile);
    // End-of-stream iterator 
    std::istream_iterator<Person> isEof;

    std::vector<Person>book;

    // iterate over the Person objects in the input
    // stream until end of file pushing each object
    // read into our vector.
    while (is != isEof) {
        book.push_back(*is);
        is++;
    }

    infile.close();

    std::cout << "x = " << x << std::endl;
    std::cout << "fx = " << fx << std::endl;

    std::cout << "Person me = " << me.name << ", age " << me.age << ", phone " << me.phone << std::endl;

    int i = 0;
    for (auto x : book) {
        i++;
        std::cout << "Person book = " << i << "  " << x.name << ", age " << x.age << ", phone " << x.phone << std::endl;
    }
    return 0;
}

int main()
{
    mainx();    // write the binary file
    mainy();    // read the binary file
    return 0;
}