Анимация
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

торы используются в низкоуровневом интерфейсе с функциями ввода-вывода операционной системы. Определены три стандартных файловых дескриптора:

О О - стандартный канал ввода;

О 1 - стандартный канал вывода;

О 2 - стандартный канал вывода ошибок.

Каналы могут связываться с файлами, консолью, процессами или другими средствами ввода-вывода.

К сожалению, стандартная библиотека С++ не поддерживает присоединение потоков данных к каналам ввода-вывода при помощи файловых дескрипторов. Это объясняется тем, что проектировщики стремились обеспечить независимость от конкретных особенностей операционных систем. Впрочем, на практике такая возможность существует, а ее единственный недостаток - влияние на переносимость программ. На сегодняшний день в стандартах интерфейсов операционных систем (таких, как POSIX или X/OPEN) не существует такой спецификации, причем ее разработка даже не планируется.

И все же поток данных можно инициализировать по файловому дескриптору. Описание и реализация возможного решения приводятся на с. 641.

Связывание потоков ввода-вывода

Иногда перед программистом возникает задача связывания двух потоков данных. Предположим, вы хотите, чтобы перед вводом данных на экран выводился текст с запросом на ввод. Другой пример ~ чтение и запись в одном потоке данных (это относится в основном к файлам). Третий характерный пример - выполнение операций с потоком данных в разных форматах. Все эти примеры будут рассмотрены далее.

Нежесткое связывание функцией tie

При связывании потока с выходным потоком данных их буферы синхронизируются так, что содержимое буфера выходного потока данных будет очищаться функцией flush() перед любой операцией ввода или вывода в другом потоке данных, В табл. 13.37 перечислены функции связывания потоков данных, определенные в классе basic ios.

Таблица 13.37. Связывание потоков данных Функция Описание

tie() Возвращает указатель на выходной поток, связанный с данным потоком

tJe(ostream* strm) Связывает поток с входным потоком, заданным аргументом, и возвращает указатель на предыдущий связанный входной поток (если он был)

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



с новым выходным потоком, следует передать указатель иа этот выходной поток в аргументе tie(). Аргумент является указателем, поскольку в нем также может передаваться О (илн NULL) для разрыва связи с выходным потоком данных. Каждый поток данных в любой момент времени может быть связан только с одним выходным потоком, но один выходной поток может быть связан с несколькими потоками данных.

По умолчанию этот механизм используется для связывания стандартного входного потока данных со стандартным выходным потоком:

Стандартные связи: std::Cin.t1e (&std:;COut); std::wcin.tie (&std::wcout);

Тем самым гарантируется, что сообщение с запросом на ввод будет выведено из буфера перед операцией ввода. Например, при выполнении следзщего фрагмента перед чтением х для cout будет автоматически вызвана функция flush():

std::cout « "Please enter x: ": std::cin » X;

Чтобы разорвать связь между потоками данных, передайте О или NULL при вызове tie(). Пример:

Отсоединение cin от выходных потоков

std::cin::tie (static cast<std::ostream*>(0)):

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

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

Связывание cout с сегг сегг.tie (&cout):

Жесткое связывание с использованием потоковых буферов

Функция rdbuf() осуществляет жесткое связывание потоков данных с помощью общего потокового буфера (табл. 13.38).

Теблица 13.38. Работа с потоковыми буферами Функция Описание

rdbuf() Возвращает указатель на потоковый буфер

rdbuf(streambuf*) Назначает потоковый буфер, определяемый аргументом, и возвращает указатель на предыдущий потоковый буфер



Функция rdbufO позволяет нескольким объектам потоков данных читать из одного входного канала или записывать в один выходной канал без нарушения порядка ввода-вывода. Однако использование нескольких потоковых буферов создает проблемы из-за буферизации операций ввода-вывода. Следовательно, применение для одного канала ввода-вывода разных потоков данных с разными буферами чревато ошибками при передаче данных. У классов basicjstream и baslc ostream имеются дополнительные конструкторы для инициализации потока данных с переданным в качестве аргумента буфером. Пример:

io/rdbufl.cpp finclude <iostreain> finclude <fstrGa[n> using namespace std:

int mainO {

Поток для шестнадцатеричного стандартного вывода ostream hexoutCcout.rdbufO): hexout.setf (ios::hex, ios::basefie1d); hexout.setf (ios::showbasG):

Переключение между десятичным и шестнадцатеричным выводом hexout « "hexout: " « 177 « " cout « "cout: " « 177 « " hexout « "hexout: " « -49 « " cout « "cout: " « -49 « "

hexout « Gnd1:

Учтите, что деструктор классов basicjstream и baslc ostream пе удаляет соответствующий потоковый буфер (который не открывается этими классами). Следовательно, чтобы передать поток данных при вызове, вместо ссылки на поток можно передать указатель на потоковый буфер:

io/rdbufZ.cpp finclude <iostreain> finclude <fstream>

void hexMultiplicationTable (std::streambuf* buffer, int num) {

std::ostream hexout(buffer);

hexout « std::hex « std::showbase:

for (int i=l; i<-num; ++i) { for (int j«l: j<-10; ++j) { hexout « i *j « :

hexout « std::endl: *



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