Анимация
JavaScript


Главная  Библионтека 

0 1 2 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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 [ 208 ] 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239

Центральный интерфейс буферов состоит из трех указателей для каждого из двух буферов. Указатели, возвращаемые функциями еЬаск(), gptr() и egptr(), образуют интерфейс к буферу чтения. Указатели, возвращаемые функциями pbaseO, pptr() и epptr(), образуют интерфейс к буферу записи. Операции чтения и записи работают с этими указателями, что приводит к соответствующей реакции в канале ввода или вывода. Далее операции чтения и записи рассматриваются отдельно.

Пользовательские буферы вывода

Для буфера, используемого для записи символов, поддерживаются три указателя, которые могут быть ползены функциями pbase(), pptr() и epptr() (рис. 13.4):

О pbaseO (*база вывода»-) - определяет начало буфера вывода;

О pptr() («указатель вывода») - определяет текущую позицию записи;

О epptr() («конец вывода») - определяет конец буфера вывода, то есть позицию, следующую за последним буферизуемым символом.

рЬа8«()

PptrO

•PPtrO

Рис. 13.4. Интерфейс буферов вывода

Символы в интервале от pbase() до pptr() (не включая символ, на который ссылается pptr()) уже записаны, но еще не выведены в соответствующий канал вывода.

Символы записываются в буфер функцией sputc(). Символ копируется в текущую позицию записи (при наличии свободной позиции), после чего указатель на текущую позицию записи увеличивается. Если буфер полон (pptr()=epptr()), то содержимое буфера вывода посылается в соответствующий канал вывода вызовом виртуальной ф)шкции overflow(). Эта функция фактически отвечает за непосредственную передачу символов некоторому «внешнему представлению» (которое на самом деле может быть внутренним, как в случае со строковыми потоками данных). Реализация overflow() в базовом классе basic streambuf возвращает только признак конца файла, означающий, что дальнейшая запись символов невозможна.

Функция sputn() позволяет записать сразу несколько символов. Она перепоручает работу виртуальной функции xsputn(), которая может оптимизироваться для более эффективной записи нескольких символов. Реализация xsputn() в классе basic streambuf вызывает sputc() для каждого символа, поэтому в ее переопределении нет абсолютной необходимости. Тем не менее в некоторых случаях запись нескольких символов реализуется более эффективно, чем последовательная запись отдельных символов, а фзгнкция xsputn() помогает оптимизировать обработку символьных последовательностей.

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



лям буфера вывода присваивается значение О или NULL. Конструктор по умолчанию делает это автоматически.

На основе изложенного материала был разработан следующий пример потокового буфера, не использующего буферизацию. То есть для каждого символа вызывается функция overflow(). Остается лишь реализовать эту функцию.

io/outbufl.hpp finclude <streafiibuf> finclude <locale> linclude <cstdio>

class outbuf : public std;:streambuf

protected: /* Главная функция вывода * - вывод символов в верхнем регистре */

virtual int type overflow (int type c) { if (c != EOF) {

Преобразование символа к верхнему регистру с - std; :toupper(c.getlocO);

Запись символа в стандартный вывод if (putchar(c) =- EOF) { return EOF;

return c;

В данном случае каждый символ, передаваемый в потоковый буфер, записывается функцией putcharO языка С. Но перед выводом символ преобразуется к верхнему регистру функцией toupper() (см. с. 692). Функция getiocO возвращает объект локального контекста, связанный с потоковым буфером (см. с. 637).

В представленном примере буфер вывода реализован специально для типа char (streambuf - специализация basic streambuf для типа символов char). При использовании другого типа символов зту функцию следует реализовать с применением класса трактовок символов, представленного на с. 659. В этом случае сравнение с с концом файла выполняется иначе. Вместо EOF должно возвращаться значение traits eof(), а если аргумент с равен EOF, следует возвращать traits: :not eof(c) (где traits - второй аргумент шаблона basic streambuf). Возможная реализация выглядит так:

io/outbuflx.hpp #1nclude <streambuf> finclude <locale> finclude <cstd1o>

template <class charT. class traits - stdi:char traits<charT> > class basic outbuf ; public std;;basic streambuf<charT.traits>



protected: /* Главная функция вывода * - вывод символов в верхнем регистре

virtual typename traits::int type overflow (typename traits::1nt type c) ( if ([traits::eq int type(c.traits::eof())) { Преобразование символа к верхнему регистру с = std::toupper(c,getloc()):

Запись символа в стандартный вывод if (putchar(c) EOF) { return traits::eof():

return traits::not eof(c):

typedef basic outbuf<char> outbuf: typedef basic outbuf<wchar t> woutbuf:

Пусть этот потоковый буфер используется в представленной ниже программе:

io/outbufl.cpp finclude <1ostream> linclude "outbuf1.hpp"

int mainO

outbuf Ob: Создание специального буфера вывода

std::ostream out(&ob): Инициализация выходного потока

созданным буфером вывода out « "31 hexadecimal: " « std::hex « 31 « std::endl:

В этом случае будет получен следующий результат: 31 HEXADECIMAL: IF

Аналогичный подход может использоваться при записи в другие приемники. Так, для инициализации объекта конструктору потокового буфера можно передать дескриптор файла, имя сокетного соединения или два других потоковых буфера, используемые для одновременной записи. Чтобы организовать вывод в соответствующий приемник, достаточно реализовать функцию overflow(). Кроме того, функцию xsputnO следует реализовать для оптимизации вывода в потоковый буфер.

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



0 1 2 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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 [ 208 ] 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239