Смекни!
smekni.com

Основы алгоритмического языка С++ (стр. 20 из 21)

Функция-элемент read

Прототип перегруженной функции-элемента read:

ostream& read(char* buff, int num);

ostream& read(signed char* buff, int num);

ostream& read(unsigned char* buff, int num);

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

Пример 5.

const MAX = 80;

char buff [MAX+1];

int len;

fstream f;

f.open("CALC.DAT", ios::in | ios::binary);

f.read((unsigned char*) &len, sizeof(len));

f.read((unsigned char*) buff, len);

f.close();

В этом примере считывается информация, записанная в предыдущемпримере.

Рассмотрим пример, выполняющий последовательный двоичный потоковыйввод/вывод. В листинге 10.2 представлен исходный код программы ARRAY.CPP.Эта программа объявляет класс, который моделирует численный динамическиймассив. Операции ввода/вывода позволяют программе читать и писать какотдельные элементы массива, так и целый массив в двоичный файл. Этапрограмма создает массивы arr1, arr2 и аrrЗ, а затем выполняет следующиезадачи:

Присваивает значения элементам массива arr1. (Этот массив имеет 10 элементов).

Присваивает значения элементам массива аrrЗ. (Этот массив имеет 20 элементов).

Отображает значения массива arr1.

Записывает элементы массива arr1 в файл ARRAY1.DAT (по одному заоперацию).

Читает элементы массива arr1 из этого файла в массив arr2 (по одному заоперацию). (Массив arr2 имеет 10 элементов, то есть он одного размера смассивом arr1).

Отображает элементы массива arr2.

Отображает элементы массива аrrЗ.

Записывает элементы массива аrrЗ в файл ARRAY3.DAT, все сразу.

Читает (все сразу) данные из файла ARRAY3.DAT и сохраняет их в массивеarr1.

Отображает значения массива arr1. (Выход показывает, что массив arr1имеет тот же размер, что и массив arr3).

Листинг 10.2. Исходный код программы ARRAY.CPP

// C++ демонстрация последовательного двоичного

// ввода/вывода

Программа листинга 10.2 объявляет версию класса Array, который похож наприводимый в главе 8 в листинге 8.2. Основное отличие в том, что здесь мыиспользовали operator[ ] для замены и функции store, и recall. Эта операцияпроверяет правильность указания индекса и возвращает значение в badIndex,если аргумент выходит за диапазон массива. В дополнение к operator[ ] мыдобавили функции-элементы writeElem, readElem, writeArray и readArray длявыполнения последовательного двоичного файлового ввода/вывода. Мы такжедобавили функции resize и getPrt как вспомогательные функции соответственнодля изменения размера массива и для возвращения указателя на соответствующийэлемент массива.

Обратите внимание также на копирующий конструктор в строке 29, и особеннона то, что он действительно ничего не определяет. Это - прием, который можетбыть использован для защиты других функций или классов от их автоматическогокопирования, когда вы знаете, что это плохо (в этом случае потому, чтоиспользуются динамические данные, содержимое которых необходимо копировать).

Функция writeElem, определенная в строках с 43 по 49, записывает одиночныеэлементы массива в выходной поток. Параметр os представляет выходной поток.Параметр index определяет элемент массива для записи. Функция writeElemвозвращает true, если индекс правильный и если операция по выводуосуществляется без ошибок. После того, как writeElem записывает элементмассива, внутренний указатель потока продвигается в следующее положение.

Функция readElem, определяемая в строках с 51 по 57, считывает одиночныйэлемент массива из входного потока. Параметр Is представляет входной поток.Параметр index определяет индекс элемента массива для чтения. Эта функциявозвращает true, если индекс массива правильный и если операция по вводуосуществляется без ошибок. После того, как readElem считывает элемент массива,внутренний указатель потока продвигается в следующее положение.

Функции writeElem и readElem позволяют экземпляру класса соответственнописать и читать элементы данных из различных потоков.

Функция writeArray, определенная в строках с 59 по 69, записывает все элементы массива в двоичный файл. Параметр filename определяет имя выходного файла. Функция открывает выходной поток и записывает значение элемента класса size, а затем и элементы динамического массива. Функция writeArray возвращает true, если массив в поток записан успешно. Иначе она возвращает false. Эта функция открывает локальный выходной поток, используя потоковуюфункцию open и передавая ей имя файла и режим ввода/вывода. Режимввода/вывода представляет собой выражение ios::out|ios::binary, котороеопределяет, что поток открывается только для вывода двоичных записей. Этафункция дважды вызывает потоковую функцию write - первый раз для записикомпонента класса size, второй - для записи элементов динамического массива.

Функция readArray, определенная в строках с 71 по 83, читает все элементымассива из двоичного файла. Параметр filename определяет имя входного файла.Функция открывает входной поток и считывает значение компонента класса size,а затем считывает элементы динамического массива. Функция readArrayвозвращает true, если она успешно считывает массив из потока. В противномслучае, возвращается false. Функция открывает локальный входной поток,используя потоковую функцию open и передавая ей имя файла и аргументырежима ввода/вывода. Аргумент режима ввода/вывода - это выражениеios::in | ios::binary, которое определяет, что поток открыт только для двоичноговвода. Функция делает два вызова потоковой функции read, первый - для чтенияэлемента класса size, и второй - для чтения элементов динамического массива.Другим свойством функции readArray является то, что она изменяет размерэкземпляра класса Array для настройки его в соответствии с данными двоичногофайла, вызывая функцию-элемент resize.Это означает, что динамический массив, который доступен посредствомэкземпляра класса, может либо уменьшаться, либо расширяться в зависимости отразмера массива, сохраняемого в файле.

Функция-элемент resize, которая начинается в строке 65, на самом деле оченьпростая. Она проверяет, является ли требуемый размер тем же, что иустановленный ранее. Если нет, то память, зарезервированная функцией dataPtr,освобождается, а затем создается новая область памяти, соответствующая новомуразмеру. Этот новый размер присваивается компоненту класса size.

Функция dispArray чаще всего является функцией-элементом, но я решилсделать ее здесь обычной функцией, чтобы лучше показать, как использованиефункции operator[ ] позволяет тем, кто работает с классом Array, обращаться кнему таким же способом, какой они применяют к элементам стандартногомассива. В этом случае есть простой цикл for, который выполняется для каждогоэлемента arr и отображает его содержимое.

Наконец, мы подходим к функции main (строка 104). Обычно она в основном только запускает функции, которые уже были созданы, для выполнения следующих задач:

Объявляет (строка 108) три экземпляра класса Array с именами arr1, arr2 иаrr3. (Первые два экземпляра имеют тот же самый размер динамическогомассива, заданный константой SIZE1, в то время как аrr3 имеет большийразмер, определенный константой SIZE2).

Объявляет (строка 111) файловый поток f и открывает его (используяконструктор потока) для доступа к файлу ARRAY1.DAT в двоичном режиме.

Использует циклы for (строки с 114 по 116), чтобы произвольно присвоитьзначения экземплярам arr1 и аrr3.

Отображает элементы экземпляра arr1 (строка 119).

Записывает элементы массива arr1 в выходной файловый поток f, используяцикл for (строка 122) для вызова функции-компонента writeElem с выходнымфайловым потоком f и переменной цикла i.

Закрывает файловый поток f, вызывая функцию-элемент close этого потока.

Открывает (строка 127) файловый поток f для доступа к файлу ARRAY1.DAT.(На это раз сообщение open определяет режим двоичного ввода)

Считывает элементы в arr2 (которому до сих пор не присваивались никакиезначения) из входного файлового потока f, используя цикл for (строка 128).

Закрывает входной поток (строка 130). D Отображает элементыэкземпляров arr2 и аrr3 (строки 132 и 133).

Записывает все содержимое аrr3, вызывая функцию-компонент writeArray.(Функция writeArray имеет аргумент имени файла ARRAY3.DAT).

Считывает массив файла ARRAY3.DAT в экземпляр arr1, вызывая функцию-компонент readArray и передавая ей в качестве аргумента имени файлаARRAY3.DAT.

Отображает новые элементы экземпляра arr1.

Файловый ввод/вывод с прямым доступом

Файловые операции ввода/вывода прямого доступа также используют потоковые функции-элементы read и write, представленные в предыдущем разделе.Stream-библиотека имеет ряд функций, позволяющих вам передвигать указательпотока в любое необходимое положение. Функция-элемент seekg - одна из такихфункций.

Функция-элемент seekg

Прототип для перегруженной функции-компонента seekg:

istream& seekg(long pos);

istream& seekg(long offset, seek_dir dir);

Параметр pos в первой версии определяет абсолютное положение байтав потоке. Во второй версии параметр offset определяет относительноесмещение, в зависимости от аргумента dir. Аргументы для последнегопараметра:

ios::beg С начала файла

ios::cur С текущей позиции файла

ios::end С конца файла

Пример

const BLOCK SIZE = 80

char buff[BLOCK_SIZE] = "Hello World!";

f.open("CALC.DAT", ios::in | ios::out | ios::binary);

f.seekg(3 * BLOCK_SIZE); // продвинутся к блоку 4

f.read((const unsigned char*)buff, BLOCK_SIZE);

cout < buff < endl;

fclose ();

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

Рассмотрим пример файлового ввода/вывода прямого доступа. В листинге10.3 приведен исходный код программы VIRTUAL.CPP и реализует виртуальныймассив. Программа выполняет следующие задачи:

Использует внутренний список имен для создания объекта виртуальногомассива.

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

Сортирует элементы объекта виртуального массива.

Отображает элементы сортированного объекта виртуального массива.

Листинг 10.3. Исходный код прогшраммы VIRTUAL.CPP