Как сохранить в бинарный файл большую структуру, а после прочитать?

226
22 июня 2018, 19:40

Структуры в моем коде вложены друг в друга, т.е. в каждой группе есть какие-то студенты, на кафедре список из этих групп

 struct Student{    
    char fullName[50];      // ФИО
    bool typeOfEducation;   // 0 - бюджет, 1 - коммерция
    int money;              // Оплата либо Стипендия
    Student* next;          // Указатель на следующего студента в группе
    Student* back;          // Указатель на предыдущего
};
struct Group{
    int number;             // Номер группы
    int count = 0;          // счетчик студентов
    Student* first;         // Первый студент в группе
    Student* last;          // Последний
    Group* next;            // Указатель на следующую группу
    Group* back;            // Указатель на предыдущую
};
struct Cathedra{
    char cathedraName[16];  // Название Кафедры
    int count;              // Счетчик групп на Кафедре
    Group* head;            // Указатель на первую группу в списке
    Group* tail;            // Указатель на последнюю
};

Для более простой структуры выполнить эту задачу получилось таким способом

struct Node{
    int n;
}

void main(){
    string path = "file.txt";
    // Пример записи
    Node N;
    N.n = 1;
    ofstream fout;
    fout.open(path, ofstream:app);
    if(!fout.is_open()) cout << "Error!";
     else {
        cout << "Файл открыт!";
        fout.write((char*)&N, sizeof(Node));
     }
     fout.close()
     // Пример чтения
     ifstream fin;
     fin.open(path);
     if(!fin.is_open()) cout << "Error!";
      else {
        cout << "Файл открыт!";
        Node Nd;
        while(fin.read((char*)&Nd, sizeof(Node))){
        }
      }
     fin.close();
     system("pause");
}

Но как работать со сложным случаем не понятно

Answer 1

Самое сложно чтение. Хотя нет, не само чтение, а связывание. Нужно понимать что тип указатель - становится не действительным (мусор), т.к. ситуация в памяти может менятся (один раз нам могут выдать одни указателе в памяти, другой раз - другие). В идеале - указатели никто не записывает. Но что б не писать и не читать указатели - программа усложнится в разы. Для чтения - нужно просто считать структуру, и проставить ссылки. Главное порядок чтения и записи соблюдать. Можно связывание обьеденить в template. Если не использовать template - всё тоже самое, только гораздо больше писанины. две last нужно будет обьявить, и две elem.

template <typename T> T* ReadBind(ofstream  * f,T * last) {
   T * elem = new elem();  /*Создадим хвост*/
   f->Read((char*)elem,sizeof(T));  // Читаем
   elem->next = NULL; /*Правим указатели*/
   elem->back = last; /* Связываем с головой */
   if (last) last->next = elem; /*Голове привяжем хвост*/
   return elem;
   }
Cathedra cathedra;
fin.read((char*)&cathedra, sizeof(Cathedra));
// В кафедре к-во есть, поэтому читаем содержимое, І итерация
cathedra.tail = 0; /*Убрать мусор*/    
for (i=0;i<cathedra.count;i++) {
   cathedra.tail = ReadBind<Group>(&fin,cathedra.tail);
   if (i==0) cathedra.head = cathedra.tail;
   // колличество на группе есть - читаем аналогично ІІ итерация
   cathedra.tail->next= 0;
   for (j=0;j<cathedra.tail->count;j++) {
      cathedra.tail->last=ReadBind<Student>(&fin,cathedra.tail->next);
      if (j==0) cathedra.tail->first = cathedra.tail->last;       
      }/*II*/
   }/*I*/

Записать чуть легче... Покажу порядок, в котором нужно записать. То же, двумя итерациями.

fout.write((char*)&cathedra, sizeof(Cathedra));         
for (Group * wg  ){    // цикл по группам - самостоятельно сделаете
  fout.write((char*)wg,sizeof(GROUP));
  for (Student * ws ) { // цикл по студентам в группе - самостоятельно
    fout.write((char*)ws,sizeof(STUDENT));
    } /*II*/
  } /*I*/

P.S. А если ещё tail и head переименовать в first и last - то цикл можно будет тоже вынести в tеmplate.

Есть ещё вариант - записываете С, G[к-во груп], считаете к-во студетнов - записываете S[к-во студентов]. Читаете так же само. Когда всё прочли - делаете связывание. это будет более трудоёмкий вариант.

READ ALSO
Явные специализации шаблона в cpp файле

Явные специализации шаблона в cpp файле

Как написать явные специализации для разных типов в другом cpp файлеНа мой взгляд все писать в хедере не очень удобно и понятно

240
работа с классами c++

работа с классами c++

у меня есть два класса TMatrix(класс для работы с матрицами) и TVector(для работы с векторами) в классе TMatrix у меня реализован метод умножения матрицы...

344
C++ tinyxml: TiXmlDocument::LoadFile(&ldquo;MyXML.xml&rdquo;) возвращает false

C++ tinyxml: TiXmlDocument::LoadFile(“MyXML.xml”) возвращает false

Не получается загрузить MyXMLxml файл, расположенный в той же директории, что и исполняемый файл приложения

175
Работа с файлами С++ (WinAPI)

Работа с файлами С++ (WinAPI)

Программа должна открывать для чтения и записи "txt" файл, в котором хранятся модели и цены ноутбуков, и при необходимости вызывать окно добавления...

349