Большинство современных операционных систем поручают управление устройствами ввода-вывода специализированным драйверам, а затем программы обращаются к ним с помощью средств библиотеки ввода-вывода, обеспечивающих максимально единообразную связь с разными источниками и адресатами данных. В общем, драйверы устройств глубоко внедрены в операционную систему и недоступны для большинства пользователей, а библиотечные средства ввода-вывода обеспечивают абстракцию ввода-вывода, так что программист не должен думать об устройствах и их драйверах.
Когда используется такая модель, вся входная и выходная информация может рассматриваться как потоки байтов (символы), обрабатываемые средствами библиотеки ввода-вывода. Наша работа как программистов, создающих приложения, сводится к следующему.
1. Настроить потоки ввода-вывода на соответствующие источники и адресаты данных.
2. Прочитать и записать их потоки.
Практические детали передачи символов с устройства и на устройство находятся в компетенции библиотеки ввода-вывода и драйверов устройств. В этой и следующей главах мы увидим, как создать систему ввода-вывода, состоящую из потоков форматированных данных, с помощью стандартной библиотеки языка С++.
• Потоки (многих) единиц данных (как правило, связанных с файлами, сетевыми соединениями, записывающими устройствами или дисплеями).
• Взаимодействие с пользователем посредством клавиатуры.
• Взаимодействие с пользователем посредством графического интерфейса (вывод объектов, обработка щелчков мыши и т.д.).
Эта классификация не является единственно возможной, а различия между тремя видами ввода-вывода не так отчетливы, как может показаться. Например, если поток вывода символов представляет собой HTTP-документ, адресуемый браузеру, то в результате возникает нечто, очень напоминающее взаимодействие с пользователем и способное содержать графические элементы. И наоборот, результаты взаимодействия посредством пользовательского графического интерфейса можно представить в программе в виде последовательности символов. Однако эта классификация соответствует нашим средствам: первые две разновидности ввода-вывода обеспечиваются стандартными библиотечными потоками ввода-вывода и непосредственно поддерживаются большинством операционных систем. Начиная с главы 1 мы использовали библиотеку iostream
и будем использовать ее в данной и следующей главах. Графический вывод и взаимодействие с пользователем посредством графического интерфейса обеспечиваются разнообразными библиотеками. Этот вид ввода-вывода мы рассмотрим в главах 12–16.
10.2. Модель потока ввода-вывода
Стандартная библиотека языка С++ содержит определение типов istream
для потоков ввода и ostream
— для потоков вывода. В наших программах мы использовали стандартный поток istream
с именем cin
и стандартный поток ostream
с именем cout
, поэтому эта часть стандартной библиотеки (которую часто называют библиотекой iostream
) нам уже в принципе знакома.
ostream
делает следующее.
• Превращает значения разных типов в последовательности символов.
• Посылает эти символы “куда-то” (например, на консоль, в файл, основную память или на другой компьютер).
Поток ostream
можно изобразить следующим образом.
Буфер — это структура данных, которую поток ostream
использует для хранения информации, полученной от вас в ходе взаимодействия с операционной системой. Задержка между записью в поток ostream
и появлением символов в пункте назначения обычно объясняется тем, что эти символы находятся в буфере. Буферизация важна для производительности программы, а производительность программы важна при обработке больших объемов данных.
istream
делает следующее.
• Превращает последовательности символов в значения разных типов.
• Получает эти символы “откуда-то” (например, с консоли, из файла, из основной памяти или от другого компьютера).
Поток istream
можно изобразить следующим образом.
Как и поток ostream
, для взаимодействия с операционной системой поток istream
использует буфер. При этом буферизация может оказаться визуально заметной для пользователя. Когда вы используете поток istream
, связанный с клавиатурой, все, что вы введете, останется в буфере, пока вы не нажмете клавишу