ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ В C++ (4-Е ИЗДАНИЕ) (часть 12) онлайн
Двоичный ввод/вывод
Форматированный файловый ввод/вывод чисел целесообразно использовать
только при их небольшой величине и малом количестве. В противном случае,
конечно, гораздо эффективнее использовать двоичный ввод/вывод, при котором
числа хранятся таким же образом, как в ОП компьютера, а не в виде символьных
строк. Целочисленные значения занимают 4 байта, тогда как текстовая версия
числа, например «12345», занимает 5 байтов. Значения типа float также всегда
занимают 4 байта. А форматированная версия «6,02314е13» занимает 10 байтов.
В следующем примере показано, как в бинарном виде массив целых чисел запи-
сывается в файл и читается из него. При этом используются две функции — write()
(метод класса ofstream), а также read() (метод ifstream). Эти функции думают о дан-
ных в терминах байтов (тип char). Им все равно, как организованы данные, что они
собой представляют, — они просто переносят байты из буфера в файл и обратно.
Параметрами этих функций являются адрес буфера и его длина. Адрес должен
быть вычислен с использованием reinterpret_cast относительно типа char*. Вторым
параметром является длина в байтах (а не число элементов данных в буфере).
Листинг 12.9. Программа BINIO
// binio.cpp
// Двоичный ввод/вывод целочисленных данных
#include <fstream> // для файловых потоков
#include <iostream>
using namespace std;
const int MAX = 100; // размер буфера
int buff[MAX]; // буфер для целых чисел
int main()
{
for(int j=0; j<MAX; j++) // заполнить буфер данными
buff[j] = j; // (0, 1, 2, ...)
Листинг 12.9 (продолжение)
// создать выходной поток
ofstream os("edata.dat", ios::binary);
// записать в него
os.write(reinterpret_cast<char*>(buff), MAX*sizeof(int) );
os.close(); // должен закрыть его
for(j=0; j<MAX; j++) // стереть буфер
buff[j] = 0;
// создать входной поток
ifstream is("edata.dat", ios::binary);
// читать из него
is.read( reinterpret_cast<char*>(buff), MAX*sizeof(int) );
for(j=0; j<MAX; j++) // проверка данных
if( buff[j] != j )
{ cerr << "Некорректные данные!\n"; return 1; }
cout << "Данные корректны\n";
return 0;
}
При работе с бинарными данными в качестве второго параметра write() и read()
следует использовать ios::binary. Это необходимо по той причине, что текстовый
режим, используемый по умолчанию, допускает несколько вольное обращение
с данными. Например, специальный символ '\n' занимает два байта (на самом
деле это и есть два действия — перевод каретки и перевод строки). Это делает
текст более удобным для чтения в DOS утилитами типа TYPE, но для бинарных
данных такой подход не годится вовсе, так как любой байт, которому не повезло
иметь ASCII-код 10, переводится двумя байтами. Аргумент ios::binary — типичный
пример бита состояния. Мы еще будем говорить об этом при обсуждении функ-
ции ореn() немного позднее в этой главе.
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48