Программирование >>  Разработка устойчивых систем 

1 ... 48 49 50 [ 51 ] 52 53 54 ... 196


Файл data.txt создается обычным способом как ASCII-файл, но для файла data.bin устанавливается флаг ios::binary, который сообщает конструктору, что файл должен создаваться как двоичный. Чтобы продемонстрировать форматирование данных в текстовом файле, мы приводим первую строку файла data.txt (строка не помещается на странице, поэтому она перенесена):

07\28\2003 12:54:40 Lat:45*2031 . Long:22*3418 . depth: 16.0164. temp: 242.0122

Функция time() стандартной библиотеки С обновляет переменную time t, на которую ссылается ее аргумент, текущим временем. На большинстве платформ последнее кодируется как количество секунд, прошедшее с 00:00:00 по Гринвичу 1 января 1970 года. Текущее время также хорошо подходит для раскрутки генератора случайных чисел функцией srand() стандартной библиотеки С, как это сделано в нашей программе.

После этого таймер увеличивается с приращением в 55 секунд, чтобы интервалы между контрольными точками выглядели менее тривиально.

Фиксированные значения широты и долготы обозначают набор измерений в одной географической точке. Глубина и температура генерируются с использованием функции rand О стандартной библиотеки С, возвращающей псевдослучайное число от нуля до RAND MAX - константы, зависящей от платформы и определяемой в заголовке <cstdlib> (обычно это наибольшее целое число, представимое на данной платформе). Для приведения числа к нужному интервалу используется оператор вычисления остатка % и верхняя граница интервала. Полученные числа являются целыми; чтобы добавить к ним дробную часть, мы снова вызываем rand() и делим 1 на полученное число (с прибавлением 1, чтобы предотвратить деление на 0).

Фактически файл data.bin задействуется как хранилище данных программы, хотя он находится на диске, а не в оперативной памяти. Функция write() записывает данные на диск в двоичной форме. Первый аргумент содержит начальный адрес исходного блока, преобразованный к типу char*, поскольку именно такой тип write() ожидает для потоков с обычной (не расширенной) кодировкой. Второй аргумент содержит количество записываемых символов, которое в данном случае совпадает с размером объекта DataPoint (тоже потому, что мы используем обычную кодировку). Поскольку объект DataPoint не содержит указателей, проблем с его сохранением на диске не возникает. Для более сложных объектов приходится разрабатывать схему сериализации с сохранением данных, на которую ссылаются указатели, и созданием новых указателей при последующей загрузке объекта. (Сериализация в книге не рассматривается - во многих библиотеках классов реализована та или иная ее разновидность.)

Проверка и просмотр данных

Чтобы проверить правильность сохранения данных в двоичном формате, можно прочитать их в память функцией read() класса потоков ввода и сравнить с текстовым файлом, созданным ранее программой Datagen.cpp. В следующем примере отформатированный результат просто записывается в cout, но вы можете перенаправить результат в файл, а затем при помощи утилиты сравнения файлов проверить его идентичность с оригиналом:

: C04:Datascan.cpp {L} DataLogger



#1nc1ude <fstream> #1nc1ude <1ostream> #include Datalogger.h #include ../require.h using namespace std:

int mainO { ifstream bindata( data.bin . ios::binary): assure(bindata. data.bin ): DataPoint d:

while (bindata.read(reinterpret cast<char*>(&d). sizeof d)) cout d endl: } III:-

Интернационализация

в наше время индустрия разработки программного обеспечения стала процветающей отраслью мирового уровня, что повышает спрос на предложения с поддержкой различных языков и культурных стандартов. Еще в конце 1980-х годов Комитет по стандартизации С включил в стандартный язык поддержку нестандартных схем форматирования данных в виде локальных контекстов. Локальный контекст представляет собой набор параметров, определяющих внешний вид некоторых выводимых значений, например дат или денежных величин. В 1990 году Комитет по стандартизации С утвердил дополнение к стандарту С, в котором определялись функции для работы с расширенными символами (тип wchar t). Тем самым обеспечивалась поддержка других кодировок, помимо ASCII и ее типичных западноевропейских расширений. Хотя в спецификации не указан точный размер расширенных символов, на некоторых платформах они реализуются в виде 32-разрядных величин и могут содержать данные в кодировке, определенной консорциумом Юникод, а также коды многобайтовых азиатских кодировок. Интегрированная поддержка расширенных символов и локальных контекстов включена в библиотеку потоков ввода-вывода.

Расширенные потоки

Расширенным потоком называется потоковый класс, поддерживающий операции с символами в расширенных кодировках. До настоящего момента во всех примерах использовались узкие потоки, содержащие экземпляры типа char (не считая последнего примера с классом характеристик из главы 3). Поскольку потоковые операции практически не зависят от базового типа символов, они обычно инкапсулируются в виде шаблонов. Так, базовое поведение потоков ввода определяется шаблоном basicjstream:

tempiate<class charT. class traits = char traits<charT> > class basicjstream {...):

Фактически все типы потоков ввода представляют собой специализации этого шаблона в виде следующих определений типов:

typedef basicjstream<char> istream: typedef basic istream<wchar t> wistream: typedef basicjfstream<char> ifstream: typedef basicjfstream<wchar t> wi fstream:



typedef basic istringstream<char> istringstream; typedef basic istringstream<wchar t> wistringstream;

Остальные типы потоков определяются аналогичным образом.

В идеале этого было бы достаточно для создания потоков с различными типами символов, но на практике все не так просто. Дело в том, что функции обработки символов для типов char и wchar t имеют разные имена. Например, для сравнения двух строк с обычной кодировкой используется функция strcmp(), а для строк с расширенной кодировкой - функция wcscmp(). Не забывайте, что поддержка расширенных кодировок появилась в языке С, в котором перегрузка функций отсутствует, поэтому пришлось использовать уникальные имена. Из-за этого обобщенный поток не мог просто вызвать strcmp() при вызове оператора сравнения. Понадобился некий механизм автоматического выбора правильной низкоуровневой функции.

Данная проблема была решена выделением различий в новую абстракцию. Операции с символами были абстрагированы в шаблон char traits, у которого имеются стандартные специализации для char и wchar t (см. главу 3). Итак, чтобы сравнить две строки, basic string просто вызывает шаблон traits::compare() (вспомните: traits является вторым параметром шаблона), который в свою очередь вызывает strcmpO или wcscmpO в зависимости от того, какая именно специализация используется (причем все это происходит незаметно для basic string).

Вам придется думать о char traits только при вызове низкоуровневых функций обработки символов; в большинстве случаев различия в именах функций для вас несущественны. Впрочем, подумайте, не стоит ли определить операторы и в виде шаблонов на тот случай, если кто-нибудь захочет их использовать с расширенными потоками.

Чтобы было понятнее, вспомните оператор для вывода Date, приведенный в начале этой главы. В исходном варианте его объявление выглядело так:

ostream& operator (ostream&. const Date&):

Такое объявление годится только для узких потоков. Обобщение производится преобразованием в шаблон на базе basic ostream:

tempiate<class charT. class traits> std::basic ostream<charT. traits>&

operator (std::basic ostream<charT. traits>& os, const Date& d) { charT fillc = os.filKos.widenCO)); CharT dash = os.widen(-); OS setw(2) d.month dash

setw(2) d.day dash

setw(4) d.year; os.fill(fillc); return os;

Также придется заменить char параметром шаблона charT в объявлении fillc, поскольку это может быть как char, так и wchar t в зависимости от специализации шаблона.

При написании шаблона тип потока неизвестен, поэтому необходим механизм автоматического преобразования символьных литералов к правильному размеру для данного потока. Задача решается благодаря функции widen() потокового класса. Например, выражение widen(-) преобразует свой аргумент в L- для расширенных потоков и оставляет его без изменений для узких потоков. Также су-



1 ... 48 49 50 [ 51 ] 52 53 54 ... 196

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика