3. Потоки ввода-вывода
Ввод-вывод в языке Си++ чаще всего делается с помощью стандартного набора классов, определенных в заголовочных файлах <iostream> и <fstream>.
3.1 Потоки и буферы
С точки зрения программы ввод-вывод – это поток байтов. При вводе программа читает байты из потока ввода при выводе – вставляет байты в поток вывода. Поток является посредником между программой и устройством ввода или вывода и служит своеобразным интерфейсом, с которым взаимодействует программа. Для управления вводом-выводом нужно осуществить две привязки: с одной стороны связать поток с программой, с другой стороны с устройством (файлом) ввода или вывода.
программа
устройство ввода-вывода
поток
Ч
устройство ввода-вывода
асто для согласования скорости передачи и приема данных используется буферизированный ввод-вывод, когда поток связывает программу и устройство не напрямую, а через промежуточный буфер:
буфер
программа
поток
Например, при использовании буферизированного ввода с клавиатуры данные в программу попадают не сразу, а после нажатия клавиши Enter. При этом происходит очистка буфера. Когда программа на языке Си++ достигает точки ввода, буфер, как правило, также очищается.
Стандартные классы istream и ostream поддерживают методы, соответственно, ввода и вывода. Эти классы являются базовыми для класса iostream, который наследует их методы. При включении в программу файла <iostream> автоматически создается 4 потоковых объекта (плюс ещё 4 для 2-ух байтовых символов):
объект cin связан со стандартным потоком ввода;
объект cout связан со стандартным потоком вывода;
объект cerr связан со стандартным потоком вывода ошибок (по умолчанию этот поток связан со стандартным устройством вывода – монитором). Поток не буферизован;
объект clog связан со стандартным потоком вывода ошибок (по умолчанию этот поток связан со стандартным устройством вывода – монитором). Поток буферизован.
Выражение
cout << "строка символов"; (*)
отправляет строку символов в буфер стандартного потока, т.к. в классе ostream таким образом определена операторная функция operator<<(). Вывод из буфера на монитор обеспечивается средствами ОС.
3.2 Перенаправление
Потоки ввода-вывода привязаны к программе с одной стороны. С другой стороны они привязаны к устройствам ввода-вывода. Изменив средствами операционной системы (ничего не меняя в программе) эту привязку, можно перенаправить эти потоки на другие устройства. Например, пусть программа называется program и в ней содержится выражение (*), выводящее строку на экран монитора. Перенаправить стандартный поток вывода программы в файл «a.dat» можно, запустив программу в командной строке:
program > a.dat
При этом поток вывода ошибок (объект cerr) остается не перенаправленным и ошибки будут, по-прежнему, выводиться на устройство по умолчанию. Следующий пример иллюстрирует перенаправление сразу двух стандартных потоков: вывода и ввода в два разных файла:
program >a.dat <b.dat
3.3 Метод write
В дополнение к многочисленным перегрузкам оператора вставки в поток <<, класс ostream содержит набор методов, осуществляющих вывод. Метод write(const char_type* s, streamsize n) выводит n символов строки s. Метод возвращает указатель на объект, который его вызвал, поэтому возможно его использование, например, следующим образом:
cout.write("строка", 6) << endl; (**)
3.4 Очистка буфера вывода. Манипуляторы
Манипулятор – это объект особого типа, который управляет потоками ввода/вывода, для форматирования передаваемой в них информации. Манипуляторы flush и endl освобождают буфер. Для манипуляторов перегружен оператор включения в поток <<, поэтому ими можно пользоваться так, как это сделано в (**). При этом манипулятор endl в отличие от flush добавляет в поток символ новой строки. Можно использовать и функциональную форму вызова манипулятора, например:
flush(cout);