Как записать структуру в файл в си
Блог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 из файлового потока прервётся на первом пробельном символе), а сохранять всё будем в текстовом файле, и читать из него же.
Чтобы всё работало, нам пришлось переписать оператор >> для своей структуры.
Программа создаст и затем прочитает такой файл:
При чтении код сам избавится от лишних пробелов в строках между лексемами, следующими после числа.
Чтение / запись структуры в файл на C
Для написания в файле, легко строку записи или междунар в файл , используя fprintf и putc, но вы , возможно , столкнулись с трудностями при написании содержимого структуры. fwrite и fread облегчают задачу, когда вы хотите писать и читать блоки данных.
-
fwrite: ниже приводится объявление функции fwrite
// C программа для написания
// структура в файл
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// структура для чтения и записи
// открыть файл для записи
outfile = fopen ( «person.dat» , «w» );
if (outfile == NULL)
fprintf (stderr, «\nError opend file\n» );
// записать структуру в файл
fwrite (&input1, sizeof ( struct person), 1, outfile);
fwrite (&input2, sizeof ( struct person), 1, outfile);
printf ( «contents to file written successfully !\n» );
printf ( «error writing file !\n» );
// C программа для чтения
// структура из файла
#include <stdio.h>
#include <stdlib.h>
// структурировать человека с 3 полями
struct person input;
// Открыть person.dat для чтения
infile = fopen ( «person.dat» , «r» );
if (infile == NULL)
fprintf (stderr, «\nError opening file\n» );
// читать содержимое файла до конца файла
while ( fread (&input, sizeof ( struct person), 1, infile))
printf ( «id = %d name = %s %s\n» , input.id,
Эта статья предоставлена Мандипом Сингхом . Если вы как GeeksforGeeks и хотели бы внести свой вклад, вы также можете написать статью с помощью contribute.geeksforgeeks.org или по почте статьи contribute@geeksforgeeks.org. Смотрите свою статью, появляющуюся на главной странице GeeksforGeeks, и помогите другим вундеркиндам.
Пожалуйста, пишите комментарии, если вы обнаружите что-то неправильное, или вы хотите поделиться дополнительной информацией по обсуждаемой выше теме.
Ввод данных из файла и вывод в файл
До этого при вводе-выводе данных мы работали со стандартными потоками — клавиатурой и монитором. Теперь рассмотрим, как в языке C реализовано получение данных из файлов и запись их туда. Перед тем как выполнять эти операции, надо открыть файл и получить доступ к нему.
В языке программирования C указатель на файл имеет тип FILE и его объявление выглядит так:
С другой стороны, функция fopen() открывает файл по указанному в качестве первого аргумента адресу в режиме чтения («r»), записи («w») или добавления («a») и возвращает в программу указатель на него. Поэтому процесс открытия файла и подключения его к программе выглядит примерно так:
Примечание. В случае использования относительной адресации текущим/рабочим каталогом в момент исполнения программы должен быть тот, относительно которого указанный относительный адрес корректен. Место нахождения самого исполняемого файла не важно.
При чтении или записи данных в файл обращение к нему осуществляется посредством файлового указателя (в данном случае, myfile).
Если в силу тех или иных причин (нет файла по указанному адресу, запрещен доступ к нему) функция fopen() не может открыть файл, то она возвращает NULL. В реальных программах почти всегда обрабатывают ошибку открытия файла в ветке if , мы же далее опустим это.
Объявление функции fopen() содержится в заголовочном файле stdio.h, поэтому требуется его подключение. Также в stdio.h объявлен тип-структура FILE.
После того, как работа с файлом закончена, принято его закрывать, чтобы освободить буфер от данных и по другим причинам. Это особенно важно, если после работы с файлом программа продолжает выполняться. Разрыв связи между внешним файлом и указателем на него из программы выполняется с помощью функции fclose() . В качестве параметра ей передается указатель на файл:
В программе может быть открыт не один файл. В таком случае каждый файл должен быть связан со своим файловым указателем. Однако если программа сначала работает с одним файлом, потом закрывает его, то указатель можно использовать для открытия второго файла.
Чтение из текстового файла и запись в него
fscanf()
Функция fscanf() аналогична по смыслу функции scanf() , но в отличии от нее осуществляет форматированный ввод из файла, а не стандартного потока ввода. Функция fscanf() принимает параметры: файловый указатель, строку формата, адреса областей памяти для записи данных:
Возвращает количество удачно считанных данных или EOF. Пробелы, символы перехода на новую строку учитываются как разделители данных.
Допустим, у нас есть файл содержащий такое описание объектов:
Тогда, чтобы считать эти данные, мы можем написать такую программу:
В данном случае объявляется структура и массив структур. Каждая строка из файла соответствует одному элементу массива; элемент массива представляет собой структуру, содержащую строковое и два числовых поля. За одну итерацию цикл считывает одну строку. Когда встречается конец файла fscanf() возвращает значение EOF и цикл завершается.
fgets()
Функция fgets() аналогична функции gets() и осуществляет построчный ввод из файла. Один вызов fgets() позволят прочитать одну строку. При этом можно прочитать не всю строку, а лишь ее часть от начала. Параметры fgets() выглядят таким образом:
Такой вызов функции прочитает из файла, связанного с указателем myfile, одну строку текста полностью, если ее длина меньше 50 символов с учетом символа ‘\n’, который функция также сохранит в массиве. Последним (50-ым) элементом массива str будет символ ‘\0’, добавленный fgets() . Если строка окажется длиннее, то функция прочитает 49 символов и в конце запишет ‘\0’. В таком случае ‘\n’ в считанной строке содержаться не будет.
В этой программе в отличие от предыдущей данные считываются строка за строкой в массив arr. Когда считывается следующая строка, предыдущая теряется. Функция fgets() возвращает NULL в случае, если не может прочитать следующую строку.
getc() или fgetc()
Функция getc() или fgetc() (работает и то и другое) позволяет получить из файла очередной один символ.
Приведенный в качестве примера код выводит данные из файла на экран.
Запись в текстовый файл
Также как и ввод, вывод в файл может быть различным.
- Форматированный вывод. Функция fprintf ( файловый_указатель, строка_формата, переменные ) .
- Посточный вывод. Функция fputs ( строка, файловый_указатель ) .
- Посимвольный вывод. Функция fputc() или putc( символ, файловый_указатель ) .
Ниже приводятся примеры кода, в которых используются три способа вывода данных в файл.
Запись в каждую строку файла полей одной структуры:
Построчный вывод в файл ( fputs() , в отличие от puts() сама не помещает в конце строки ‘\n’):
Пример посимвольного вывода:
Чтение из двоичного файла и запись в него
С файлом можно работать не как с последовательностью символов, а как с последовательностью байтов. В принципе, с нетекстовыми файлами работать по-другому не возможно. Однако так можно читать и писать и в текстовые файлы. Преимущество такого способа доступа к файлу заключается в скорости чтения-записи: за одно обращение можно считать/записать существенный блок информации.
При открытии файла для двоичного доступа, вторым параметром функции fopen() является строка «rb» или «wb».
Тема о работе с двоичными файлами достаточно сложная, для ее изучения требуется отдельный урок. Здесь будут отмечены только особенности функций чтения-записи в файл, который рассматривается как поток байтов.
Функции fread() и fwrite() принимают в качестве параметров:
- адрес области памяти, куда данные записываются или откуда считываются,
- размер одного данного какого-либо типа,
- количество считываемых данных указанного размера,
- файловый указатель.
Эти функции возвращают количество успешно прочитанных или записанных данных. Т.е. можно «заказать» считывание 50 элементов данных, а получить только 10. Ошибки при этом не возникнет.
Пример использования функций fread() и fwrite() :
Здесь осуществляется попытка чтения из первого файла 50-ти символов. В n сохраняется количество реально считанных символов. Значение n может быть равно 50 или меньше. Данные помещаются в строку. То же самое происходит со вторым файлом. Далее первая строка присоединяется ко второй, и данные сбрасываются в третий файл.