При записи структуры в файл мы копируем биты из памяти в файл. Очень важно взять правильные размеры записываемой сущности. Посмотрим простейший пример:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
//Запись структуры в бинарный файл clang Листинг #1 #include <string.h> #include <iostream> #include <fstream> using namespace std; struct Worker { char Name[256]; //Фамилия сотрудника float salary; //Заработная плата int age; //Возраст рабочего }; int main() { const char *FName="C:\\MyFiles\\Worker.bin"; //Путь к файлу. Вписывайте свой. Worker teacher; //teacher - Записываемый в файл объект структуры Worker w1; //w1 - читаемый из файл объект структуры /*ЗАПОЛНЯЕМ СТРУКТУРУ*/ strncpy(teacher.Name, "Pupkin", 256); //в случае работы с Си-строками, нужно копировать строку в строку teacher.age = 30; teacher.salary = 1523.99; /*Записываем структуру в файл*/ ofstream f1(FName, ios::binary | ios:out); f1.write((char*)&teacher, sizeof(teacher)); f1.close(); /*Читаем структуру из файла */ ifstream f2(FName, ios::binary | ios:in); f2.read((char*)&w1, sizeof(teacher)); f2.close(); /*Вывод данных на экран*/ cout << w1.Name << '\t' << w1.age << '\t' << w1.salary << '\n'; } |
1 |
cout << sizeof(teacher) << " == " << sizeof(teacher.age) + sizeof(teacher.Name) + sizeof(teacher.salary); |
1 2 3 4 5 6 7 |
#pragma pack(push, 1) struct Worker { int age; //Возраст рабочего double salary; //Заработная плата char Name[256]; //Фамилия сотрудника }; #pragma pack (pop) |
1 2 3 |
Worker *teacher = new Worker; //указательная переменная teacher sizeof(teacher); //даёт не размер структуры, а размер указателя delete teacher; |
//Запись структуры в бинарный файл, если на структуру указывает указатель clang Листинг #2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
#include <string.h> #include <iostream> #include <fstream> using namespace std; #pragma pack(push, 1) struct Worker { int age; //Возраст рабочего double salary; //Заработная плата char Name[256]; //Фамилия сотрудника }; #pragma pack (pop) int main() { const char *FName="C:\\MyFiles\\Worker.bin"; //Путь к файлу. Вписывайте свой. Worker *teacher; //teacher - Записываемый в файл объект структуры Worker w1; //w1 - читаемый из файл объект структуры teacher = new Worker; /*ЗАПОЛНЯЕМ СТРУКТУРУ*/ strncpy(teacher->Name, "Pupkin", 256); //в случае работы с Си-строками, нужно копировать строку в строку teacher->age = 30; teacher->salary = 1523.99; /*Записываем структуру в файл*/ ofstream f1(FName, ios::binary | ios:out); f1.write((char*)teacher, sizeof(Worker)); //<--- Эта строчка изменилась в двух местах!!! f1.close(); delete teacher; /*Читаем структуру из файла */ ifstream f2(FName, ios::binary | ios:in); f2.read((char*)&w1, sizeof(Worker)); f2.close(); /*Вывод данных на экран*/ cout << w1.Name << '\t' << w1.age << '\t' << w1.salary << '\n'; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
#include <string.h> #include <iostream> #include <fstream> using namespace std; #pragma pack(push, 1) struct Worker { int age; //Возраст рабочего double salary; //Заработная плата char *Name; }; #pragma pack (pop) int main() { const char *FName="C:\\MyFiles\\Worker.bin"; //Путь к файлу. Вписывайте свой. Worker teacher; //teacher - Записываемый в файл объект структтуры Worker w1; //w1 - читаемый из файл объект структуры teacher.Name = new char[256]; /*ЗАПОЛНЯЕМ СТРУКТУРУ*/ strncpy(teacher.Name, "Pupkin", 256); //в случае работы с Си-строками, нужно копировать строку в строку teacher.age = 30; teacher.salary = 1523.99; /*Записываем структуру в файл*/ ofstream f1(FName, ios::binary | ios:out); f1.write((char*)&(teacher.salary), sizeof(teacher.salary)); f1.write((char*)&(teacher.age), sizeof(teacher.age)); f1.write((char*)(teacher.Name), sizeof(teacher.Name) * 256); //Из-за указательной переменной пришлось делать поэлементную запись f1.close(); delete []teacher.Name; { /*Читаем структуру из файла */ w1.Name = new char[256]; ifstream f2(FName, ios::binary | ios:in); f2.read((char*)&(w1.salary), sizeof(w1.salary)); f2.read((char*)&(w1.age), sizeof(w1.age)); f2.read((char*)(w1.Name), sizeof(w1.Name) * 256); //Из-за указательной переменной пришлось делать поэлементную запись f2.close(); /*Вывод данных на экран*/ cout << w1.Name << '\t' << w1.age << '\t' << w1.salary << '\n'; } delete []w1.Name; } |
Статья полностью переписана 27.03.2018
Выше сказано про другое. То о чем говорилось тогда я исправил тогда.
На строку выделено 255 символов.
В строку вводится строка
Последний символ в строке — признак окончания строки
За признаком окончания строки все что угодно. Это мусор.
Добавить строчку
и мусора не будет видно в файле.
А теперь я объясню подробнейшем образом что такое (char*)&X .
Действительно, (char*)&X не удобная и устаревшая запись. Следует писать reinterpret_cast&X
reinterpret_cast(UkVol); гораздо неудобнее и выглядит уродливо.
То не устаревшая форма записи, то форма записи в стиле Си. Да, считается, что преобразования делать лучше не в стиле Си.
А еще лучше использовать std::string и не использовать указатели
Спасибо большое, работает!