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!" и сохраняю этот файл. Теперь я буду читать этот файл в бинарном режиме.Вы можете записать в файл несколько строчек.

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

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

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

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

При сложном строении классов или активном участии указателей в классах объекты часто сериализуют. Я сериализовать ничего не умею, поэтому и показать, как такое вытворять — не могу.

Если эта статья оказалась для вас полезной и вы чему-то научились, то я рад.

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

  1. Юрий:

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

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

      =========

  2. Дмитрий:

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

  3. Татьяна:

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

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

  4. Татьяна:

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

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

  5. Шлюпка:

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

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

  6. Дмитро:

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

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

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

  7. Дмитро:

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

  8. Kost:

    Не знаю как в c++, а в русском нет слова "нету"

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Поиск

 
     

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

https://www.litres.ru/aleksandr-mikushin/zanimatelno-o-mikrokontrollerah/?lfrom=15589587
Яндекс.Метрика