Как создать динамический массив структур чтения данных из двоичного файла - PullRequest
0 голосов
/ 19 сентября 2018

У меня есть struct, который описывает объекты данных, хранящиеся в двоичном файле.Структура выглядит следующим образом:

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

Это загружается через чтение из двоичного файла, и число объектов данных в файле может варьироваться.Когда я объявляю struct как установленный предел через const, все работает.К сожалению, двоичный файл может содержать меньше или больше данных, чем объявлено.

Как я могу динамически увеличивать массив по мере необходимости в зависимости от количества объектов, хранящихся в двоичном файле?

Ответы [ 2 ]

0 голосов
/ 21 сентября 2018

Вы не указываете фактический формат двоичного файла, поэтому я предполагаю, что он содержит массив предоставленных вами структур.

Таким образом, ваш базовый алгоритм будет выглядеть примерно так:

  • создать std::vector структуры, как в std:vector <Sum_str > myVect;
  • , начиная с следующей точки в соответствующей точке двоичного файла, я предполагаю смещение 0, чтение двоичной записи, что означает чтениев структуре как двоичный объект
  • поместите его в вектор, как в myVect.push_back(obj);
  • , продолжайте это чтение объекта и вставляя в вектор, пока не достигнете надлежащей конечной точки, которую я предполагаюявляется концом файла

Основным и зависимым предположением является то, что двоичный файл содержит ноль или более из того, что составляет двоичное изображение массива структур, Sum_str.Это важно по той причине, что вы хотите убедиться, что:

  • размер объекта Sum_str в файле совпадает с размером Sum_str объекта в памяти
  • что компоновка и смещения элементов объекта Sum_str в файле - это та же компоновка и смещения элементов, что и Sum_str объекта в памяти

Если двоичный файл содержит толькомассив структурных данных, тогда вы можете оценить количество структур, содержащихся в файле, и создать std::vector с начальной емкостью, которая приближается к оценке.См. Начальная емкость вектора в C ++ , а также Используя файловые потоки C ++ (fstream), как вы можете определить размер файла? , который предоставляет способ подсчета размера файла,tellg() метод получения размера файла не является надежным, хотя, похоже, что с двоичными файлами в Windows и Linux он достаточно близок.

См. Чтение и запись двоичного файла , а также Как читать двоичный файл в вектор беззнаковых символов , а также c ++ Класс чтения / записи из / в двоичный файл и C ++ двоичные файлы и итераторы: уход от1: 1 с использованием 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;
}
0 голосов
/ 19 сентября 2018

Вы не используете правильный контейнер, если размер ваших массивов может быть больше, чем заданные вами максимумы 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
};

Если вы ограничены массивами, то заполняйте массивы только до их соответствующей длины.Не забудьте поместить нулевые завершающие символы в конец данных, чтобы вы не случайно прочитали свои массивы при печати содержимого.Также используйте #define для ваших размеров массива вместо магических чисел.

Если вы не уверены, сколько структур Sum_str вам нужно, вам следует использовать контейнер, который будет соответствовать вашим требованиям.Ваши требования требуют контейнер, который может измениться в размере, поэтому вы должны использовать вектор

std::vector<Sum_str> my_container;
...