Как записать структуру в файл в си
БлогNot. Структура со строками string и файловые чтение/запись массива таких структур
Структура со строками string и файловые чтение/запись массива таких структур
В отличие от этого примера, используем в структурном типе данных более удобные в обращении и современные строки string и файловые потоки вместо классических си-строк char * и файлов из <cstdio> . Лекции по всем этим темам можно найти в оглавлении.
В итоге должна получиться программка, которая покажет непосредственное задание значений полям структурной переменной и ввод значений полей с консоли, а также запись файла структур и последующее его контрольное чтение. Проверяться она будет в консоли Visual Studio 2015, проект создан как вот здесь.
В начале файла укажем нужные библиотеки и директивы, в комментариях написано, для чего какая служит:
Опишем структурный тип данных, включающий в себя идентификатор (номер) записи, две строки для хранения имени и даты рождения, а также вещественное поле money для хранения, например, зарплаты:
Мы не указываем какие-либо ограничения на длину строки, потому что сами будем управлять этим.
Так как программа может завершиться тремя способами — нормально, при ошибке записи файла и при ошибке его чтения, напишем функцию error с аргументом n (номер ошибки), которая будет за это отвечать. Ошибка номер ноль, как принято в C++, будет означать нормальное завершение. Вообще такую «общую точку выхода» зачастую полезно делать в процедурно-ориентированном коде:
Функция для ввода данных с консоли input получает аргументами адрес структуры a , куда нужно заносить данные (это может быть, в том числе, и адрес элемента массива структур) и идентификатор записи i , остальные поля записи она запрашивает у пользователя.
В реальности стоило бы снабдить код большим количеством проверок корректности данных и вводом их в некую буферную запись, откуда потом скорректированные данные могут быть скопированы в массив или в файл.
Также обратите внимание, что мы не должны «резать» поля структуры кодом вроде
но с отдельной буферной строкой имели бы на это право, конечно же, прежде, чем копировать её в запись, предназначенную для постоянного хранения.
Со всеми этими оговорками, простейшая функция ввода записи получилась такой:
Функция output , соответственно, выводит в консоль поля записи a , переданной аргументом:
При корректных данных должны получиться столбцы правильной ширины.
Главной программе осталось русифицировать консоль и создать массив записей, для простоты предусмотрим там всего 2 элемента:
Первый элемент с id , равным нулю, зададим программно, а второй введём с консоли:
Откроем файл notes.dat для записи и поместим туда данные, заодно печатая их в консоль:
Обратите внимание, что применение sizeof к составному объекту string некорректно, приходится писать в бинарный файл отдельными полями.
После закрытия файла, откроем его вновь для чтения и покажем прочитанные в цикле записи на экране, после чего можно сделать нормальный выход из программы:
Вы понимаете, что наш файл — двоичный, и открывать его текстовым редактором бессмысленно.
Вот лог работы нашей программы:
скриншот 16-ричного вида файла (см. комменты)
- писать и читать только string.c_str() в бинарные файлы, сведя задачу к предыдущей ссылке (но тогда не нужны и string , а можно делать классически на char * );
- всё же отказаться от бинарных, а ограничиться текстовыми файлами и парсить полученные через getline строки;
- предусмотреть в формате файла одновременное сохранение длины строковых данных объекта string .
В последнем случае имеем примерно такой подход (проверен не на структурах, а на паре строк).
Программа для записи набора string в бинарный файл:
Потом читаем это (возможно, с точностью до кодировки):
В моей консоли Visual Studio 2015 обе программки сработали. Итак, если строка string является полем структуры, разницы в подходах нет.
P.P.S. Ну и, раз пошла такая пьянка, теперь разрешим строкам string в массиве структур иметь произвольную длину и содержать пробелы (по умолчанию чтение string из файлового потока прервётся на первом пробельном символе), а сохранять всё будем в текстовом файле, и читать из него же.
Чтобы всё работало, нам пришлось переписать оператор >> для своей структуры.
Программа создаст и затем прочитает такой файл:
При чтении код сам избавится от лишних пробелов в строках между лексемами, следующими после числа.
Как записать структуру в файл в си
Хотя функции getc()/putc() позволяют вносить в файл отдельные символы, но фактически мы имеем дело с бинарными файлами. Если мы записываем в файл строку, то в принципе мы даже можем открыть записанный файл любом текстовом редакторе и понять, что там было записано. Но не всегда данные могут представлять строки. И чтобы более наглядно разобраться с работой с бинарными файлами, рассмотрим еще одни пример — с записью-чтением структуры из файла.
В данном случае запись и чтение структуры выделены в отдельные функции: save() и load() соответственно.
Для записи в функции save() через параметр struct person *p получаем указатель на сохраняемую структур. Фактически его значением является начальный адрес блока памяти, где располагается структура.
Функция putc записывает отдельный символ в файл, однако нам надо записать структуру. Для этого мы создаем указатель на символ (который по сути представляет один байт) и устанавливаем этот указатель на начало блока памяти, выделенного для структуры.
То есть в данном случае мы получаем адрес в памяти первого байта из блока памяти, которая выделена для структуры. И затем мы можем пройтись по всему этому блоку и получить отдельные байты и занести их в файл:
И в данном случае нам не важно, какие поля имеет структура, какой она имеет размер. Мы работаем с ней как с набором байт и заносим эти байты в файл. После занесения каждого отдельного байта в файл указатель c в блоке памяти перемещается на один байт вперед.
При чтении файла в функции load() используется похожий принцип только в обратную сторону.
Во-первых, для считывания структуры из файла мы выделяем блок динамической памяти для хранения прочитанных данных:
После этого указатель ptr будет указывать на первый адрес блока из 20 байт (наша структура занимает 20 байт = 16 символов и 4 байта для числа int ).
Затем так как при прочтении мы получаем символы, устанавливаем указатель на первый байт выделенного блока и в цикле считываем данные из файла в этот блок:
Здесь стоит обратить внимание на то, что в данном случае на самом деле считываем даже не символ, а числовой код символа в переменную типа int и только потом передаем значение указателю c. Это сделано для корректной обработки окончания файла EOF. Это значение может представлять любое отрицательное число. И если бы мы сохранили отрицательное число (например, возраст пользователя был бы отрицательным), то оно было бы некорректно интерпретировано при чтении как конец файла, и итоговый результа был бы неопределенным. Поэтому более правильно считывать именно числовой код символа в переменную int, а затем числовой код передавать в char.
Запись и чтение массива структур
Выше приведен пример по работе с одной структурой. Но, как правило, при работе с файлами мы оперируем не одной структурой, а каким-то набором структур. Поэтому усложним задачу и сохраним и считаем из файла массив структур:
Данная задача усложнена тем, что нам надо хранить массив структур, количество которых точно может быть неизвестно. Один из вариантов рещения этой проблемы состоит в сохранении некоторой метаинформации о файле в начале файла. В частности, в данном случае в начале файла сохраняется число записанных структур.
Запись во многом аналогична записи одной структуры. Сначала устанавливаем указатель на число n , которое представляет количество структур, и все байты этого числа записываем в файл:
Затем подобным образом записываем все байты из массива структур — устанавливаем указатель на первый байт массива структур и записываем size байт в файл:
При чтении нам придется файктически считывать из файла два значения: количество структур и их массив. Поэтому при чтении два раза выделяется память. Вначале для количества элементов:
Как записать в файл структуру с указателями?
Как записать её в файл таким образом, чтобы записались не адреса, а значения? С учетом того, что все указатели указывают на массивы.
Учитывая, что Вы используете массивы в C-стиле, то Вы должны где-то хранить кол-во элементов этого массива. На основании Вашего кода непонятно, где хранится это значение(-я). Потом это double***pppdWeights; — где инициализируется, как и т.п. Выкладывайте, пожалуйста, больше кода, иначе проблема может быть неясна.
Далее, Вы пишете чтобы записались не адреса а значения.
Это был пример для указателя на int . Для массива будет как-то так:
Для вывода в файл вместо стандартного потока cout используете ofstream и выводите. Надеюсь, Вы знаете, как работать со стандартными потоками вывода.
Можно воспользоваться дедовским методом:
Извините, что упростил структуру. Но суть кода в следующем: записываем в файл содержимое структуры в бинарном виде; переходим в конец файла и записываем значение разыменовонного указателя; повторяем смещение и запись для всех указателей. Далее обратный процесс: читаем с начала файла структуру (указатели могут ссылаться уже на освобожденную память); выделяем новую память для указателей; смещаемся от начала файла на размер структуры; читаем объем по типу указателя; повторяем для всех указателей.
У меня такое решение получилось
Дизайн сайта / логотип © 2023 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2023.7.31.43551
Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.
Запись структуры в файл
Как правильно будет записать структуру данных в файл, что бы затем без проблем его можно было считать?
Запись структуры в файл
есть структура struct base < int id; char name; >; typedef struct base office; .
Запись структуры в файл
Что я не так делаю ?Облазил много тем и так и не понял почему оно не работает. int main()< int.
Запись структуры в файл
Дан файл (testNEW.txt), в котором записана информация о ноутбуках. Часть этой информации нужно.
Запись структуры в файл
Здравствуйте! Исходный код записи структуры в файл: #include <stdio.h> typedef __int8 .
Сообщение от sharpey
Сообщение от sharpey
Сообщение от Дантe
Вы имеете в виду блок кода в строках 154-156?
Сообщение от Дантe
А Вы точно уверены, что оперируете именно структурами, а не всем массивом структур сразу, при чтении и записи?
Полезная информация о fopen. Далее: у Вас структура knigi содержит описание полей Nr, god как целых чисел, поэтому файл должен быть не текстовым, а двоичным. Поэтому режим открытия файла должен быть "ab+" или "ab".
Сообщение от Дантe
Чтение из файла поструктурно можно осуществить в строке 47 так:
fread(&kniga[j], sizeof(struct knigi), 1, fail_gr);
И добавьте заголовочный файл stdbool.h, без его указания gcc ругался на булевы переменные в режиме C99.
Хотите полезный совет? Научитесь использовать отладчик, встроенный в IDE (или отдельно gdb) — много вопросов можно решить быстрее и самостоятельно, чем дождаться советов гуру. )
Рекомендую отличные книги на эту тему:
— Джон Роббинс "Отладка приложений для Microsoft .NET и Microsoft Windows", 2004 год;
— Крис Х. Паппас, Уильям Х. Мюррей III "Отладка в C++. Руководство для разработчиков", 2001 г.
Если надо их — обращайтесь в личку.