Как записать сразу всю структуру (содержащую string) в бинарный файл?
Структуру необходимо записать таким методом, чтобы потом запустить отдельно другую функцию, которая сможет прочитать файл, но перед этим не добавлять записи в файл(ну то есть чисто чтение)
Пробовала так: после того как пользователь введет string посчитать string.size() + 1 и приплюсовать sizeof(int), но после чтение из файла выдает какой-то бред
- Вопрос задан более трёх лет назад
- 4582 просмотра
15 комментариев
Средний 15 комментариев
justAnotherCluelessUser @justAnotherCluelessUser
«но после чтение из файла выдает какой-то бред»
Почему так много людей верят в ясновидящих??
Тут их особо нет. вроде.
Так что весь код на текстообменник(типа пастбин) и ссылку.
SUkI3 @SUkI3 Автор вопроса
anketa ar; int size = 0; int k = 0; fstream fout ("test.dat", ios::binary | ios::app); if(!fout) < coutcout> k; for(int i = 0; i> ar.year; cin.ignore(); cout fout.close();
Потом вот это запускаю отдельно
fstream file("test.dat", ios::binary | ios::in); if(!file) < coutif (getline( file, ar.fio, '\0' )) do < cout while(getline( file, ar.fio, '\n' )); file.close();

Вы понимаете, что тут происходит?
size = sizeof(ar.year) + ar.fio.length() + 1; fout.write((char*)&ar,sizeof(size));
SUkI3 @SUkI3 Автор вопроса
RabraBabr, передаем байты и размер, который получился после как пользователь ввел данные

SUkI3, какие байты? И размер чего? Внимательно подумайте.
SUkI3 @SUkI3 Автор вопроса
RabraBabr, байты которые преобразовали адрес указателя структуры, а размер, ну просто размер цифра, или похоже я не правильно понимаю работу записи в бинарник. (
Алексей Сергей @dev_random
SUkI3, почитайте про POD типы. В приведенном коде std::string не является POD типом и соответсвенно вся anketa тоже. При fout.write(&ar, sizeof(ar)) в файл попадут внутренние поля std::string (включая указатель (адрес) на строку), но не сама строка!
SUkI3 @SUkI3 Автор вопроса
Алексей Сергей, да я знаю, что структура не POD, если б было все так просто.
Поэтому и вопрос на тостере
Так возможно создать алгоритм который записывает структуру со string так, как если б там не было string, а были только POD типы?
Алексей Сергей @dev_random
SUkI3, смотрите в сторону сериализаторов.
Есть много либ на гитхабе. Например я такую пару раз использовал: https://github.com/USCiLab/cereal
Есть еще либа в бусте, но не все хотят буст в зависимости тащить. https://www.boost.org/doc/libs/1_70_0/libs/seriali.
Алексей Сергей @dev_random
SUkI3, забыл еще упомянуть, что сериализаторы обычно предоставляют несколько форматов для выходного файла. Легко делается как-минимум: бинарный, бинарный-кроссплатформа, текст, json и xml.
SUkI3 @SUkI3 Автор вопроса
Алексей Сергей, сериализаторы какое страшное слово, спасибо, почитаем)


Roman @myjcom Куратор тега C++
SUkI3, в чем смысл бинарной записи обычной строки. Байт на байт, шило на мыло.
SUkI3 @SUkI3 Автор вопроса
Roman, у string методы, модификаторы есть уже готовые, вроде как легче работаться должно

Roman @myjcom Куратор тега C++
SUkI3,
при чем тут сейчас методы и модификаторы?
вы данные (data) сохраняете, данные в std::string это динамический массив char.
если использовать
struct anketa < int year; char fio[64]; >;
то все гораздо проще и с чтением и с записью.
Со string как раз таки мороки больше.
#include #include #include #include using namespace std; struct Data < int value = 0; string str; >; ofstream& operator<<(ofstream& ofs, Data& d) < size_t sz = d.str.size(); ofs.write(reinterpret_cast(&d.value), sizeof(d.value)); ofs.write(reinterpret_cast(&sz), sizeof(sz)); ofs.write(d.str.c_str(), sz); return ofs; > ifstream& operator>>(ifstream& ifs, Data& d) < ifs.read(reinterpret_cast(&d.value), sizeof(d.value)); size_t sz; ifs.read(reinterpret_cast(&sz), sizeof(sz)); d.str.resize(sz); ifs.read(reinterpret_cast(&*d.str.begin()), sz); return ifs; > int main() < Data d = ; ofstream ofs("D:\\file.bin", ios_base::binary); ofs > d2; assert(d.value == d2.value && d.str == d2.str); cin.get(); >
Запись структуры в бинарный файл и чтение из него
Здравствуйте! Помогите решить проблему! У нас есть структура data_count, в которой хранятся полученные параметры файлов типа .doc. Бинарный файл должен являтся некой "базой данных", в котором должны хранится записи с этими параметрами.
struct data_count
long int W;
long int C;
long int Pg;
long int Par;
long int Ln;
long int CWS;
>;
data_count X[10000];
При каждом запуске программы мы открываем файл для определения количества записанных в него записей, и в последующую будем записывать структуру с новыми полученными параметрами.
//---получение количества записей в файле---------------------------
Далее делаем сверку новых полученных параметров с теми, которые уже записаны в файл. Если совпадающих параметров нет - записываем структуру с новыми данными в файл.
. MessageBox(NULL, "Файл успешно принят", "Статус проверки", MB_OKCANCEL);
X[quantity].W = WCount;
X[quantity].C = CCount;
X[quantity].Pg = PgCount;
X[quantity].Par = ParCount;
X[quantity].Ln = LnCount;
X[quantity].CWS = CWSCount;
Не пойму почему, но всё отлично работает только с первыми двумя записями: и проверяет, и сверяет, и пишет в файл. После получения параметров 3-го документа структра записывается на место второй записи в файле (переменная quantity получает значение 2, а не 3). Элемент X.W, уже записанной в бинарный файл структры, никогда не будет нулевым, т.к показывает количество слов в файле .doc (этот момент в программе предусмотрен). Помогите разобраться, как структуру с новыми полученными данными записать после последней записи в файле. заранее спасибо.
Как записать структуру в бинарный файл c
Хотя функции getc()/putc() позволяют вносить в файл отдельные символы, но фактически мы имеем дело с бинарными файлами. Если мы записываем в файл строку, то в принципе мы даже можем открыть записанный файл любом текстовом редакторе и понять, что там было записано. Но не всегда данные могут представлять строки. И чтобы более наглядно разобраться с работой с бинарными файлами, рассмотрим еще одни пример - с записью-чтением структуры из файла.
#include #include struct person < char name[16]; int age; >; int save(char * filename, struct person *p); int load(char * filename); int main(void) < char * filename = "person.dat"; struct person tom = < "Tom Smith", 21 >; save(filename, &tom); load(filename); return 0; > // запись структуры в файл int save(char * filename, struct person *p) < FILE * fp; char *c; int size = sizeof(struct person); // количество записываемых байтов fp = fopen(filename, "wb"); //открываем файл для бинарной записи if (!fp) // если не удалось открыть файл < printf("Error occured while opening file \n"); return 1; >// устанавливаем указатель на начало структуры c = (char *)p; // посимвольно записываем в файл структуру for (int i = 0; i < size; i++) < putc(*c++, fp); >fclose(fp); return 0; > // загрузка из файла структуры int load(char * filename) < FILE * fp; char *c; int i; // для считывания одного символа // количество считываемых байтов int size = sizeof(struct person); // выделяем память для считываемой структуры struct person * ptr = malloc(size); fp = fopen(filename, "rb"); // открываем файл для бинарного чтения if (!fp) < printf("Error occured while opening file \n"); return 1; >// устанавливаем указатель на начало блока выделенной памяти c = (char *)ptr; // считываем посимвольно из файла while ((i = getc(fp))!=EOF) < *c = i; c++; >fclose(fp); // вывод на консоль загруженной структуры printf("%-20s %5d \n", ptr->name, ptr->age); free(ptr); return 0; >
В данном случае запись и чтение структуры выделены в отдельные функции: save() и load() соответственно.
Для записи в функции save() через параметр struct person *p получаем указатель на сохраняемую структур. Фактически его значением является начальный адрес блока памяти, где располагается структура.
Функция putc записывает отдельный символ в файл, однако нам надо записать структуру. Для этого мы создаем указатель на символ (который по сути представляет один байт) и устанавливаем этот указатель на начало блока памяти, выделенного для структуры.
c = (char *)p;
То есть в данном случае мы получаем адрес в памяти первого байта из блока памяти, которая выделена для структуры. И затем мы можем пройтись по всему этому блоку и получить отдельные байты и занести их в файл:
for (int i = 0; i
И в данном случае нам не важно, какие поля имеет структура, какой она имеет размер. Мы работаем с ней как с набором байт и заносим эти байты в файл. После занесения каждого отдельного байта в файл указатель c в блоке памяти перемещается на один байт вперед.
При чтении файла в функции load() используется похожий принцип только в обратную сторону.
Во-первых, для считывания структуры из файла мы выделяем блок динамической памяти для хранения прочитанных данных:
struct person * ptr = (struct person *) malloc(size);
После этого указатель ptr будет указывать на первый адрес блока из 20 байт (наша структура занимает 20 байт = 16 символов и 4 байта для числа int ).
Затем так как при прочтении мы получаем символы, устанавливаем указатель на первый байт выделенного блока и в цикле считываем данные из файла в этот блок:
c = (char *)ptr; // считываем посимвольно из файла while ((i = getc(fp))!=EOF)
Здесь стоит обратить внимание на то, что в данном случае на самом деле считываем даже не символ, а числовой код символа в переменную типа int и только потом передаем значение указателю c. Это сделано для корректной обработки окончания файла EOF. Это значение может представлять любое отрицательное число. И если бы мы сохранили отрицательное число (например, возраст пользователя был бы отрицательным), то оно было бы некорректно интерпретировано при чтении как конец файла, и итоговый результа был бы неопределенным. Поэтому более правильно считывать именно числовой код символа в переменную int, а затем числовой код передавать в char.
Запись и чтение массива структур
Выше приведен пример по работе с одной структурой. Но, как правило, при работе с файлами мы оперируем не одной структурой, а каким-то набором структур. Поэтому усложним задачу и сохраним и считаем из файла массив структур:
#include #include struct person < char name[20]; int age; >; int save(char * filename, struct person *st, int n); int load(char * filename); int main(void) < char * filename = "people.dat"; struct person people[] = < , , , >; int n = sizeof(people) / sizeof(people[0]); save(filename, people, n); load(filename); return 0; > // запись в файл массива структур int save(char * filename, struct person * st, int n) < char *c; // для записи отдельных символов // число записываемых байтов int size = n * sizeof(struct person); FILE * fp = fopen(filename, "wb"); if (!fp) < printf("Error occured while opening file\n"); return -1; >// записываем количество структур c = (char *)&n; for (int i = 0; i < sizeof(n); i++) < putc(*c++, fp); >// посимвольно записываем в файл все структуры c = (char *)st; for (int i = 0; i < size; i++) < putc(*c, fp); c++; >fclose(fp); return 0; > // загрузка из файла массива структур int load(char * filename) < char *c; // для считывания отдельных символов int m = sizeof(int); // сколько надо считать для получения размера массива int n; // количество структур в массиве FILE * fp = fopen(filename, "r"); if (!fp) < printf("Error occured while opening file\n"); return -1; >// выделяем память для хранения количества данных int *ptr_count = malloc(m); // считываем количество структур c = (char *)ptr_count; // пока не считаем m байт, сохраняем байт в выделенный блок для размера массива while (m > 0 && (*c = getc(fp)) != EOF) < c++; m--; >//получаем число элементов n = *ptr_count; free(ptr_count); // освобождаем память // выделяем память для считанного массива структур struct person * ptr = malloc(n * sizeof(struct person)); // устанавливаем указатель на блок памяти, выделенный для массива структур c = (char *)ptr; // считываем посимвольно из файла while ((*c= getc(fp))!=EOF) < c++; >// перебор загруженных элементов и вывод на консоль printf("\nFound %d people\n\n", n); for (int i = 0; i < n; i++) < printf("%-5d %-10s %5d \n", i + 1, (ptr + i)->name, (ptr + i)->age); // или так // printf("%-5d %-10s %5d \n", i + 1, ptr[i].name, ptr[i].age); > free(ptr); fclose(fp); return 0; >
Данная задача усложнена тем, что нам надо хранить массив структур, количество которых точно может быть неизвестно. Один из вариантов рещения этой проблемы состоит в сохранении некоторой метаинформации о файле в начале файла. В частности, в данном случае в начале файла сохраняется число записанных структур.
Запись во многом аналогична записи одной структуры. Сначала устанавливаем указатель на число n , которое представляет количество структур, и все байты этого числа записываем в файл:
c = (char *)&n; for (int i = 0; i
Затем подобным образом записываем все байты из массива структур - устанавливаем указатель на первый байт массива структур и записываем size байт в файл:
// посимвольно записываем в файл все структуры c = (char *)st; for (int i = 0; i
При чтении нам придется файктически считывать из файла два значения: количество структур и их массив. Поэтому при чтении два раза выделяется память. Вначале для количества элементов:
int *ptr_count = malloc(m);
Затем мы считываем первые 4 байта из файла для получения числа:
c = (char *)ptr_count; while (m > 0 && (*c = getc(fp)) != EOF) < c++; m--; >//получаем число элементов n = *ptr_count;
Затем аналогичные действия проделываем для массива структур.
struct person * ptr = malloc(n * sizeof(struct person)); // устанавливаем указатель на блок памяти, выделенный для массива структур c = (char *)ptr; // считываем посимвольно из файла while ((*c= getc(fp))!=EOF)
И результатом программы должен быть вывод считанных данных:
Found 4 people 1 Tom 23 2 Alice 27 3 Bob 31 4 Kate 29
Как записать, а после прочитать из бинарного файла структуру?
Суть такая, пишу аля "Архиватор", суть такая, имеется структура:
struct File
После чего начинаю обрабатывать файл, который вводит пользователь:
P.S.: Кст, да, пишу на Си под Linux.>

Я определяю размер файла, который на вход, после чего выделяю память для ПЕРЕМЕННОЙ структуры, чтобы потом fread в эту переменную содержимое файла, сохраняю всю структуру в файл. Почему-то бинарный файл меньше исходного, хотя там структура. Исх. файл 13 байт "Hello world!", а бинарный где-то 6-7 байт получается, не понимаю почему так.
И как потом прочитать эту структуру, если я выделял память отдельно еще под содержимое?
Пробовал выделить для структуры память в видеstruct File *test = malloc(struct File) и прочитать файл fread(test, РАЗМЕР_ФАЙЛА, 1, ФАЙЛ), но выдает ошибку, не могу разобраться, как прочитать файл? Но у меня еще есть ощущение, что я неправильно делаю запись в бинарник, насчет того, что выделяю память отдельно для переменной еще.
- Вопрос задан более трёх лет назад
- 499 просмотров
4 комментария
Простой 4 комментария