С++ для начинающих. Запись структуры в файл и чтение структуры из файла

Сайт не является учебником по программированию. Это только небольшой авторский сборник информации в помощь начинающим программистам.

На этой странице моих материалов по C++ вы можете почитать про то, как записывать структуру в файл и как её считывать. В свое время я потратил много времени на поиски вразумительных материалов, но тогда это всё было без толку и первые мои попытки описать эту тему были ошибочны. Сейчас такая информация ищется на просторах интернета, но немного тяжеловато. Не буду мусолить эту тему, перейду к делу.

Я буду исходить из того, что в полях структуры не будет ни одного указателя. В полях структуры будут находится только примитивные типы данных. Будет там и массив символов (куда же без него). Дело в том, что указатели в полях структуры являются большим источником проблем и многих заблуждений. Это тот случай когда двойственность указателей паразитирует и ведет себя наиболее яростно по отношению к программисту. Начинающий программист легко вводится в заблуждение тем, что программа может выдавать результат за правду, но на самом деле всё не так как ему кажется. Очень часто происходит так, что в файл записывается не значение указателя, а сам указатель. Значение остается в памяти и поэтому при попытке прочитать файл, очень часто значение получается правильное. Из файла считывается указатель, с указателя берется адрес для вытаскивания значения и значение вытаскивается не из файла, а из памяти. Так как значение распологается в памяти, то нет вероятности того, что оно там лежит в целости и сохранности. Файл — это одно, а память другое. Из-за такого рода проблемы совет избегать указателей очень даже актуален.

Я признаюсь: «Понятия не имею как записывать в файл структуру, если внутри ее полей находятся указатели». Я могу записывать каждое поле по отдельности, но это не то, чего бы мне хотелось на самом деле. На самом деле мне хотелось бы записывать структуру сразу целиком и такая возможность для структур существует. (Единственная оговорка, что мое: «существует» относится к структурам без указателей. С указателями я не знаю (думается, что для структур с указателями обрабатывать поля нужно только по отдельности).

Итак, чтобы записать структуру в файл нужно, чтобы была такая структура, которую мы хотим записать. Логично? – логично. Поэтому Начинаем с написания простой структуры

Наверное это достаточно просто и понятно. Создали структуру и переменную типа созданной структуры. Теперь осталась самая важная часть — записать структуру в файл. Чтобы записать структуру в файл, нужно знать размеры структуры.
Снова поговорю об указателях. Если в полях структуры есть указатели, то правильный размер структуры узнать не получится. Размер объекта из указателя вытащить нельзя. Существует возможность узнать размер самого указателя, но не объекта на который он указывает. Это порождает некоторые заметные трудности. Указатель – это все-таки указатель, сложная гадость.
Возвращаемся к записи несложной структуры в файл. Чтобы записать структуру в файл, нужно сообщить компилятору адрес структуры, приведенный к типу указатель на char и размер записываемой структуры. Делается это так

Очень хорошо строку с записью в файл я объяснить не смогу. Этот синтаксис проще запомнить, главное, что в первом параметре используется указатель на char из-за чего используется приведение типов к такому указателю, а после запятой идет второй параметр. Вторым параметром сообщается размер, который нужно использовать для записи в файл. Те кто знакомы с приведениями типов должны понимать, что происходит, кто не знаком имеет смысл привыкать. Понимание еще придет.

  • (char*)&X —> Неудобная запись. Читать ее нужно справа налево. Адрес структуры X приводится к типу указатель на char. Это необходимо, чтобы сообщить методу write (read) адрес структуры в нужном ему виде. Внимательно прочитайте справа-налево, единственное: &X = адрес структуры X, и имейте ввиду, что такой вид обратного чтения при работе с указателями бывает часто удобен.

Вот такой пример записи структуры в файл и чтения данных из файла в структуру для начинающих. Этот пример относительно прост. Главное понимать, что когда вы открываете файл для обработки, то после обработки обязательно его закрывать. Что при чтении или записи структуры из файла по описанному алгоритму, нужно привести адрес структуры к типу указатель на char и сообщить размер структуры. Следует помнить, что указатели: «Сложная гадость» и использовать их может или ввести в заблуждение или заставить написать больше сложного кода. Также хочу лишний раз обратить внимание на то, что в символьный массив нельзя присвоить строку и чтобы записать в него значение, нужно использовать приемы копирования.

статья полностью переписана 07 января 2014г.

    если увидите похожие статьи, но с указателями, то знайте — они ошибочны и мне их нужно поправить. Просьба о них сообщить. Сам я все отследить не могу, но и в заблуждения вводить не хочу

Все комментарии на сайте проверяются, поэтому ваш комментарий может появиться не сразу. Для вставки кода в комментарий используйте теги: [php]ВАШ_КОД[/php]

12 комментариев: С++ для начинающих. Запись структуры в файл и чтение структуры из файла

  • Sergio говорит:

    Что-то мне подсказывает, что в предпоследнем примере (33 строка) и последнем (39 строка) косяк…

    Для записи в файл должно быть ios::out.

    Автор сайта отвечает:
    Истинно так. Спасибо.

    Sergio говорит:
    А вот в последнем примере в 47 строке зря исправили: нужно in 😀

  • Максим говорит:

    никакой строки тут в файл не сохраняется, туда сохраняются структура, т.е поля структуры X,
    а именно: указатель на стороку, и сайз соответственно, т.е. не больше 8 байт. сама строка остаётся в памяти. если она будет очищена и перезаписана то обращение к игреку вызовет ошибку, да и в данном случае при использовании минимально вменяемого отладчика ругнулся бы на попытку очищения игрека после икса, так как к этому моменту память уже очищена.
     
    а память выделенная игреку как-раз безвозвратно потеряна и очистится только с выходом из программы.

    Автор сайта отвечает:
    позднее посмотрю. скорее всего это так и есть.
    Исправлено

  • магомед говорит:

    использовал ваш код в своей программе как выше сказано так и есть как только программу закрываю она выводит какие то левые символы а это не очень хорошо. как именно со всеми значениями сохранить данные не знаете?

    • admin говорит:

      Выше сказано про другое. То о чем говорилось тогда я исправил тогда.
      На строку выделено 255 символов.
      В строку вводится строка
      Последний символ в строке — признак окончания строки
      За признаком окончания строки все что угодно. Это мусор.

      Добавить строчку

      и мусора не будет видно в файле.

  • магомед говорит:

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

  • магомед говорит:

    случайно в описание написал вопрос. прочтитайте там

    • admin говорит:

      Я не очень понимаю
      я и из программы выходил и перезагружался и все норм. и в разных компиляторах проверял

      ничего и не изменил.

      Вероятно проблема в том, что в структуре массивы и значит целиком ее не запишешь. Я просто в упор не вижу когда ошибка случается.

  • магомед говорит:

    в общем я скопировал ваш код и вставил себе все отлично заработало если запустить заполнение через цикл а когда вручную ввожу оно сохраняет одно только последнее значение почему то

    • admin говорит:

      Я не заполняю в цикле структуру. Я в цикле присваиваю нули не инициализированным переменным. Без этого в них хранится любой мусор. А только после этого работаю с этой структурой.

      Я заполняю только одно значение, цикл для этого не требуется.
      Я Ваш код не видел, поэтому догадаться о проблеме у меня не выйдет.
      Также я понятия не имею как у Вас происходит ручное заполнение.
      Мой левел экстрасенсорики — нуб

  • RomixERR говорит:

    А теперь я объясню подробнейшем образом что такое (char*)&X .

    Действительно, (char*)&X не удобная и устаревшая запись. Следует писать reinterpret_cast&X

    • admin говорит:

      reinterpret_cast(UkVol); гораздо неудобнее и выглядит уродливо.
      То не устаревшая форма записи, то форма записи в стиле Си. Да, считается, что преобразования делать лучше не в стиле Си.
      А еще лучше использовать std::string и не использовать указатели

  • Влад говорит:

    Спасибо большое, работает!

Добавить комментарий

Ваш e-mail не будет опубликован.

Поиск

 
     

Яндекс.Метрика

НАГРАДИ АВТОРА САЙТА
WEBMONEY
R375024497470
U251140483387
Z301246203264
E149319127674

Программист на ночь ставит два стакана. Один - с водой, другой - без воды. Первый - на случай, если захочет пить, Второй - если не захочет.

Выражаю свою признательность

  • Максиму очень признателен за указание на мои ошибки и неточности.
  • Sergio ===> за оказание помощи в исправлении моих ошибок
  • Gen ===> за правильное стремление помочь другим новичкам и выявления моих ошибок