C++ для начинающих. Знакомство работы с бинарными файлами

Эта статья написана для того, чтобы поверхностно ознакомить новичков со способом создания и обработки бинарного файла на языке С++.
В нашем, человеческом представлении, файлы в компьютере могут хранится в двух вариантах: понятно компьютеру и понятно нам. Понятные нам файлы — это текстовые файлы, понятные компьютеру — это бинарные файлы.
В зависимости от задачи бывает удобно выбрать один из этих вариантов. Например, для настроек какой-нибудь игры или программы может быть удобно хранить файлы в текстовом виде, чтобы можно было взять открыть любым текстовым редактором и поменять какую-нибудь настройку быстро и просто. А вот сохранения игр удобнее хранить в бинарных файлах. Как минимум это лёгкая защита от применения читов. Ведь что за игра, если тебе система дала 100 монет, а ты открываешь файл, пишешь 1000.000 монет, покупаешь самое крутое и такой прям классный-преклассный игрок. Я к тому, что выбор двоичного или текстового файла может зависеть от ситуации.
Обычно в двоичных файлах хранят какие-то определённые структуры данных. Многие из моих читателей до структур и классов ещё не дошли, поэтому приводимый мной пример максимально простой.
Чаще всего работа с бинарными файлами происходит в стиле языка С.

К сожалению, в С++ есть небольшой непорядок, иногда вводящий нас, новичков, в уныние.
  • Когда мы говорим о бинарных данных, тип char выступает в роли типа byte
В С++ нету типа byte , а вместо типа byte используют тип char. Согласно правилам языка С++, тип char оказывается наименьшей единицей информации. Из-за этого восприятие нами ситуации в целом немного искажается, ведь мы видим char*, а на самом деле это как byte*
В наших компьютерах используется такая модель памяти, где одна ячейка занимает 1 байт. А один символ char гарантировано, как утверждают в стандарте, должен залезать в эту ячейку. Поэтому, в зависимости от ситуации, тип char можно трактовать или как символьный тип, или как байтовый тип. Файлы, хранящие последовательность байтов, называют бинарными файлами. Это связано с тем, что байт делится на биты, а биты представляют собой двоичные цифры. Слово бинарный переводится как двоичный.
Чтобы мы могли записать какое-нибудь значение в бинарном представлении, нам нужно для начала вывести это бинарное представление, а чтобы записалось правильное количество байт, нужно явно указывать это количество. Это выглядит приблизительно следующим образом:
(char*)&x
Так мы делаем строку байтов для того, чтобы отдать потоку, открытому в двоичном режиме

sizeof(x)
Так мы ограничиваем число уходящих в поток байтов нужным числом

Здесь есть аналогия с символьным массивом, но поскольку у нас не символьная строка, а байтовая строка, то ограничение происходит не нуль-символом, а явным указанием числа числа байт. В зависимости от заявленного для переменной типа переменная может занимать от одного до нескольких байт в памяти компьютера, и при записи переменных мы должны внимательно следить, чтобы число байтов, указываемое нами, строго било с числом байт, занимаемых переменной в памяти. Мы переносим байты из памяти в файл. Чтобы байты переносились как именно байты, мы интерпретируем переменную как строку байтов.
Приблизительно такие ужасы у нас происходят при записи в бинарном формате данных в файл.
Для того, чтобы правильно читать данные из файлов, хранящих данные в бинарном виде, нужно знать общую структуру хранения внутри файла. В нашем случае структура хранения внутри файла весьма проста: в файле хранится два числа, одно целое, одно дробное. Т. е. нужно знать, что хранится внутри файла, и в каком порядке оно хранится. Чтобы получить возможность читать данные, хранимые внутри файлов, нам нужно подключить заголовочный файл fstream и использовать тип ifstream или тип fstream. Я буду использовать первый.

Всё очень напоминает запись в файл, только происходит обратный процесс. Опять же, мы следим за числом цепляемых байтов и переносим их из файла в память компьютера.
  • ifstream — специальный тип, объекты которого выполняют роль файловых переменных, читающих файлы
  • ofstream — специальный тип, объекты которого выполняют роль файловых переменных, записывающих файлы
Для того, чтобы вам проще было работать с бинарными файлами, нужно запомнить две простые истины:
  1. Выводите строку байтов
  2. Следите за размерами
На самом деле для компьютеров нет различия между бинарными файлами и текстовыми файлами, это различие существует только из-за нашего восприятия мира. Вы легко можете прочитать самый простейший текстовый файл при бинарном подходе, при этом вам текст будет точно так же понятен, как он понятен и сам по себе, в блокноте. Текстовые файлы — это только-лишь частный случай бинарных файлов. Просто создайте какой-нибудь текстовый файл в удобном месте (нежелательно, чтобы путь к текстовому файлу содержал символы русского алфавита). Например, я создам файл "C:\MyFiles\text.txt", в этот файл запишу какой-то текст. Советую сначала не использовать русские символы, потому что у некоторых из вас могут быть трудности с кодировками, а я объяснить решения не смогу. В общем, пишу в текстовый файл текст: "Hello, my file!" и сохраняю этот файл. Теперь я буду читать этот файл в бинарном режиме.Вы можете записать в файл несколько строчек.

Тут вам как и в обычном случае: нужно заполнять байтовую строку байтами, получаемыми из файла, и следить за числом передаваемых байт. Только нужно сделать дополнительное обнуление символьного массива, чтобы при выводе на экран к полученному из файла тексту не прилипал мусор.
Подводный камень, который может вас ждать в ближайшем будущем — это попытка записать в файл значение, на которое ссылается указательная переменная. В случае работы с указателями в файл будет записываться не значение, с которым связана указательная переменная, а сама указательная переменная. Поэтому не записывайте в файл указательные переменные, если вы не записываете адреса памяти. А адреса памяти вам вряд ли придётся записывать в файл, потому что работа с адресами памяти в полномочиях операционной системы. Вам нужно или сразу записывать значения не указательного характера, или переводить указательный вариант в вариант неуказательный. Будьте особенно осторожны, если вам надо записывать данные, связанные с указательными переменными.
Дальше совсем новичкам можно пока не читать, а просто принять к сведению. В бинарные файлы можно быстро и легко сохранять объекты тривиальных, т. е. простых по своему строению, классов и читать в объекты подходящих классов данные из таких бинарников.

Здесь всё то же самое: приведение к байтовой строке, особое внимание на число байт. Если сохраняем объект в файл целиком, то и читать его лучше целиком, а не отдельные его части. Современные компьютеры выравнивают поля классов, чтобы работа со значениями, хранимыми в объектах, происходила быстрее. Эти выравнивания могут повлиять на выполнение поставленной вами задачи. Когда вы сохраняете объект полностью и потом читаете его полностью, то вам не надо задумываться о выравниваниях, а если пробовать выцепить отдельные части сохранённого объекта как одного целого, то не факт, что всё у вас выцепится правильно, где-нибудь когда-нибудь произойдёт несовпадение и сохранённые в файл данные не будут выглядеть практически полезными.
При сложном строении классов или активном участии указателей в классах объекты часто сериализуют. Я сериализовать ничего не умею, поэтому и показать, как такое вытворять — не могу.
Если эта статья оказалась для вас полезной и вы чему-то научились, то я рад.

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

11 комментариев: C++ для начинающих. Знакомство работы с бинарными файлами

  • Юрий говорит:

    не работает код в Visual studio. начиная с объявления заголовочных файлов




    0



    0
    • admin говорит:

      Для Visual Studio первые три строчки такие

      =========




      0



      0
  • Дмитрий говорит:

    Чушь! Не работает. Записывается не строка в файл а указатель.




    0



    0
  • Татьяна говорит:

    Смущают не строчки, а текст после кода.
    iostream, ifstream — это не команды, это конструкторы. А вот после того как с их помощью сконструировали файловые объекты, вот тогды используются методы — члены класса: для чтения read, для записи write




    0



    0
    • admin говорит:

      Правильнее сказать: «классы».(не конструкторы)
      вы же не можете вызвать конструктор класса в самостоятельном виде.
      Я исправлю. Спасибо, что показали.




      0



      0
  • Татьяна говорит:

    Да, классы, но в таком написании вызываются конструкторы файловых объектов (неявно). И уж точно никакие н команды. Для С++ это вообще какой-то странный термин.




    0



    0
    • admin говорит:

      я уже исправил.
      надеюсь лучше стало.
      и я не знаю чем вам не нравится термин: «команда».
      В конкретном месте, я действительно неправильно его применил и, благодаря вам, исправил, но
      Команда — это элементарное действие, операция, выполняемые вычислительным устройством
      т.е. написали a+b, написали команду сложения, использовали оператор сложения.
      написали ifstream — использовали команду создания класса для описания объекта.
      русский язык велик и могуч и то, что другие языки не могут так широко использоваться означает, что совсем не обязательно кто-то там ошибается, если использует фразеологию не по книжному варианту.




      0



      0
  • Шлюпка говорит:

    ifstream in(«C://1.txt»,ios::binary|ios::in); //Открыли для только для чтения в бинарном режиме

    Два слова «для», исправьте.




    0



    0
  • Дмитро говорит:

    Спасибі величезне!

    термин: «команда» це дійсно негарно. Він плутає і ріже слух (зір0!

    Конструктор відразу пояснює суть справи — і це саме те що треба




    0



    0
  • Дмитро говорит:

    Тобто ж клас — рівно зрозуміло!




    0



    0

Поиск

 
     

Случайная книга в электронном формате

https://www.litres.ru/b-louson/izuchaem-html5-4955202/?lfrom=15589587
Яндекс.Метрика
НАГРАДИ АВТОРА САЙТА
WEBMONEY
R375024497470
U251140483387
Z301246203264
E149319127674

Демотиватор

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

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