Потоки в С++
В языке Си++ нет особых операторов для ввода или вывода данных. Вместо этого имеется набор классов, стандартно поставляемых вместе с компилятором, которые и реализуют основные операции ввода-вывода. Библиотека классов для ввода-вывода решает две задачи. Вопервых, она обеспечивает эффективный ввод-вывод всех встроенных типов и простое, но тем не менее гибкое, определение операций ввода-вывода для новых типов, разрабатываемых программистом. Во-вторых, сама библиотека позволяет при необходимости развивать её и модифицировать.
Понятие поток Поток — это абстрактное понятие, относящееся к любому переносу данных от источника к приемнику. Чтение данных из потока называется извлечением, вывод в поток - помещением, или включением. Поток определяется как последовательность байтов и не зависит от конкретного устройства, с которым производится обмен. Обмен с потоком для увеличения скорости передачи данных производится, через специальную область оперативной памяти — буфер. Фактическая передача данных выполняется при выводе после заполнения буфера, а при вводе — если буфер исчерпан. По направлению обмена потоки можно разделить на: - входные (данные вводятся в память), - выходные (данные выводятся из памяти) - двунаправленные (допускающие как извлечение, так и включение). По виду устройств, с которыми работает поток, можно разделить потоки на стандартные, файловые и строковые.
Стандартные потоки iostream. h l cout, cin и cerr cout - стандартный вывод, cin – стандартный ввод, cerr – стандартный поток сообщений об ошибках. l cout и cerr выводят на терминал и принадлежат к классу ostream, cin имеет тип istream и вводит с терминала. l
Основные классы потоков ios — базовый класс потоков; istream — класс входных потоков; ostream — класс выходных потоков; iostream — класс двунаправленных потоков; istrstream — класс входных строковых потоков; ostrstream — класс выходных строковых потоков; strstream — класс двунаправленных строковых потоков; ifstream — класс входных файловых потоков; ofstream — класс выходных файловых потоков; fstream — класс двунаправленных файловых потоков; streambuf — буферизация потоков.
Вывод осуществляется с помощью перегруженной операции >>, ввод с помощью операции <<. cout << "Пример вывода: " << 34; int x; cin >> x;
Форматирование функции-члены; l флаги; l манипуляторы l
Класс ios class ios { // набор форматирующих методов public: int width(int w); // установить поле width int width() const; char fill(char); // установить символ заполнения char fill() const; // вернуть символ заполненияlong flags(long f); long flags() const; long setf(long setbits, long field); long setf(long); long unsetf(long); int precision(int); // установить точность для float int precision() const; //. . . };
Примеры: форматирующие методы #include
Форматирующие флаги // Класс ios const int my_io_options = enum { ios: : left|ios: : oct|ios: : showpoint|ios: : fixed; skipws = 0 x 0001, //пропуск пробелов cout. flags(my_io_options); left = 0 x 0002, //выравнивание right = 0 x 0004, internal = 0 x 0008, cout. setf(ios: : scientific, ios: : floatfield); dec = 0 x 0010, //система счисления cout. setf(0, ios: : floatfield); // вернуться oct = 0 x 0020, к стандартному hex = 0 x 0040, cout. setf(ios: : hex, ios: : basefield); showbase = 0 x 0080, //показать основание с. с. showpoint = 0 x 0100, //нули в конце uppercase = 0 x 0200, //большие буквы для основания showpos = 0 x 0400, scientific = 0 x 0800, //научная форма числа fixed = 0 x 1000, //с фиксир. точкой unitbuf = 0 x 2000, //сброс в выходной поток stdio = 0 x 4000 }; static const long basefield; // dec | oct | hex static const long adjustfield; // left | right | internal static const long floatfield; // scientific | fixed
Манипуляторы – это объекты особых типов, которые управляют тем, как ostream или istream обрабатывают последующие аргументы. Некоторые манипуляторы могут также выводить или вводить специальные символы. endl при выводе перейти на новую строку; ends вывести нулевой байт (признак конца строки символов); flush немедленно вывести и опустошить все промежуточные буферы; dec выводить числа в десятичной системе (действует по умолчанию); oct выводить числа в восьмеричной системе; hex выводить числа в шестнадцатеричной системе счисления; setw (int n) установить ширину поля вывода в n символов (n – целое число); setfill(int n) установить символ-заполнитель; этим символом выводимое значение будет дополняться до необходимой ширины; setprecision(int n) установить количество цифр после запятой при выводе вещественных чисел; resetiosflags( long l. Flags ); Сбросить флаги ввода-вывода setiosflags( long Установить флаги ввода. вывода
Примеры: манипуляторы #include “iostream” #include “iomanip” void main() { double values[] = { 1. 23, 35. 36, 653. 7, 4358. 24 }; char *names[] = { "Zoot", "Jimmy", "Al", "Stan" }; for( int i = 0; i < 4; i++ ) cout << setw( 6 ) << names[i] << setw( 10 ) << values[i] << endl; } Zoot 1. 23 Jimmy 35. 36 Al 653. 7 Stan 4358. 24 setw и width не отсекают данные при выводе
int x = 53; cout << "Десятичный вид: " << dec << x << endl << "Восьмеричный вид: " << oct << x << endl << "Шестнадцатеричный вид: " << hex << endl ; double x; // вывести число в поле общей шириной // 6 символов (3 цифры до запятой, // десятичная точка и 2 цифры после запятой) cout << setw(6) << setprecision(2) << x << endl; int x; // ввести шестнадцатеричное число cin >> hex >> x; Манипулятор ws переключает вводимый поток в такой режим, при котором все пробелы (включая табуляцию, переводы строки, переводы каретки и переводы страницы) будут вводиться. По умолчанию эти символы воспринимаются как разделители между атрибутами ввода.
Флаги: выравнивание double values[ ] = { 1. 23, 35. 36, 653. 7, 4358. 24 }; char *names[ ] = { "Zoot", "Jimmy", "Al", "Stan" }; for ( int i = 0; i < 4; i++ ) cout << setiosflags( ios: : left ) << setw( 6 ) << names[i] << resetiosflags( ios: : left ) << setw( 10 ) << values[i] << endl; Zoot Jimmy Al Stan 1. 23 35. 36 653. 7 4358. 24
Точность double values[] = { 1. 23, 35. 36, 653. 7, 4358. 24 }; char *names[] = { "Zoot", "Jimmy", "Al", "Stan" }; for ( int i = 0; i < 4; i++ ) cout << setiosflags(ios: : left) << setw( 6 ) << names[i] << resetiosflags( ios: : left ) << setw( 10 ) << setprecision( 1 ) << values[i] << endl; Zoot 1 Jimmy 4 e+001 Al 7 e+002 Stan 4 e+003 Добавить перед циклом cout << setiosflags(ios: : fixed); Zoot 1. 2 Jimmy 35. 4 Al 653. 7 Stan 4358. 2 Заменить ios: : fixed flag на ios: : scientific Zoot 1. 2 e+000 Jimmy 3. 5 e+001 Al 6. 5 e+002 Stan 4. 4 e+003
Создание собственных манипуляторов без аргументов #include
Операции << и >> для потоков В классах iostream операции >> и << определены для всех встроенных типов языка Си++ и для строк (тип char*). Если мы хотим использовать такую же запись для ввода и вывода других классов, определенных в программе, для них нужно определить эти операции. class String { public: String() { str=new char[1]; str[0]=0; } friend ostream& operator<<(ostream& os, const String& s); friend istream& operator>>(istream& is, String& s); private: char* str; int length; }; ostream& operator<<(ostream& os, const String& s) { os << s. str; return os; } istream& operator>>(istream& is, String& s) { // длина строк не более char tmp[1024]; is >> tmp; if (s. str != 0) { delete [] s. str; } s. length = strlen(tmp); s. str = new char[s. length + 1]; if (s. str == 0) { // обработка ошибок s. length = 0; return is; } strcpy(s. str, tmp); String x; . . . cin >> x; cout << "this is a string: " << x;
#include “iostream” class Date { int mo, da, yr; public: Date( int m, int d, int y ) { mo = m; da = d; yr = y; } friend ostream& operator<< ( ostream& os, Date& dt ); friend istream& operator>> ( istream& is, Date& dt ) }; ostream& operator<< ( ostream& os, Date& dt ) { os << dt. mo << '/' << dt. da << '/' << dt. yr; return os; } istream& operator>> ( istream& is, Date& dt ) { is >> dt. mo >> dt. da >> dt. yr; return is; } void main() { Date dt( 5, 6, 92 ); cout << dt; cin >> dt; }
Дополнительные функции ostream и istream class ostream : public virtual ios { //. . . public: ostream& flush(); //вывести из потока //позиционирование потока ostream& seekp(streampos); ostream& seekp(streamoff, seek_dir); // вернуть текущую позицию streampos tellp(); //. . . }; class istream : public virtual ios { //. . . public: int peek(); //след. символ ввода // вернуть считанный символ в поток istream& putback(char c); istream& seekg(streampos); istream& seekg(streamoff, seek_dir); streampos tellg(); //. . . }; istream& putback(char ch ); #include
#include
Состояние потоков Методы класса ios для проверки состояния потока: class ios { public: int eof() const; // дошли до конца файла int fail() const; // следующая операция // будет неудачна int bad() const; // поток испорчен int good() const; // следующая операция будет // успешной void clear(int _i) // очистка всех битов // состояния //. . . }; Значения, обозначающие эти состояния: class ios { public: enum io_state { goodbit=0, eofbit=1, failebit=2, badbit=4, }; //. . . }; Проверить состояние потока можно следующим образом: switch (cin. rdstate()) { case ios: : goodbit: // последняя операция cin была успешной break; case ios: : eofbit: // конeц файла break; case ios: : failebit: // некоторый анализ ошибки break; case ios: : badbit: // cin возможно испорчен break; }
Ввод-вывод файлов Класс ofstream (вывод) l Класс ifstream (ввод) l Класс fstream (двунаправленный файловый поток). l Эти классы являются производными от классов istream, ostream и iostream соответственно, поэтому они наследуют перегруженные операции << и >>, флаги форматирования, манипуляторы, методы, состояние потоков и т. д.
Файлы По способу доступа файлы можно разделить на: l l последовательные, чтение и запись производятся с начала байт за байтом, файлы с произвольным доступом, допускающие чтение и запись в указанную позицию. Допустимые операции с файлами: создание потока; l открытие потока и связывание его с файлом; l обмен (ввод/вывод); l уничтожение потока; l закрытие файла. Конструкторы без параметров создают объект соответствующего класса, не связывая его с файлом Конструкторы с параметрами создают объект соответствующего класса, открывают файл с указанным именем и связывают файл с объектом: l ifstream(const char *name, int mode = ios: : in); ofstream(const char *name, int mode = ios: : out | ios: : trunc); fstream(const char *name, int mode = ios: : in | ios: : out);
Режимы открытия файла ios: : app при записи данные добавляются в конец файла, даже если текущая позиция была перед этим перемещена; ios: : ate при создании потока текущая позиция помещается в конец файла; однако, в отличие от режима app, запись ведется в текущую позицию; ios: : in поток создается для ввода; если файл уже существует, он сохраняется; ios: : out поток создается для вывода (режим по умолчанию); ios: : trunc если файл уже существует, его прежнее содержимое уничтожается, и длина файла становится равной нулю; режим действует по умолчанию, если не заданы ios: : ate, ios: : app или ios: : in; ios: : binary ввод-вывод будет происходить в двоичном виде, по умолчанию используется текстовое представление данных; ios: : nocreate Если файл не существует, выдать ошибку ios: : noreplace Если файл существует, выдать ошибку
Запись чтение в/из файл(а) #include
Файлы со смешанными данными int main(){ char ch; ofstream out(“test"); if(!out) { cout << "Cannot open file 'test' for writing" << endl; return 1; } char str[80], *p; out << 123 << "this is a test" << 23; out << "Hello there!" << 99 << "bye" << endl; out. close(); // Чтение файла ifstream in('test", ios: : i n | ios: : nocreate); if(!out) { cout << "Cannot open file 'test' for reading" << endl; return 1; } do{ p = str; ch = in. peek(); // выяснение типа символа if(isdigit(ch)){ while(isdigit(*p = in. get())) p++; in. putback(*p); // возврат в поток *р = ' '; //конец строки cout << "Number: " << atoi(str); } else if(isalpha(ch)){ while(isalpha(*p = in. get())) p++; in. putback(*p); // возврат в поток *р = ' '; cout << "String: " << str: } else in. get(); // пропуск cout << endl; } while(!in. eof()); in. close(); return 0; }
Текстовые файлы #include
Вывод/ввод в файловый поток #include
Вывод/ввод в файловый поток #include
Двоичные файлы Данные можно вывести в двоичный поток с помощью методов write или put: ostream& write(const char* pch, int n. Count); ostream& put(char ch); Метод write выводит указанное количество байтов (n. Count), расположенных в памяти, начиная с адреса pch. Метод put выводит один байт. Для того чтобы переместить текущую позицию, используется метод seekp: ostream& seekp(streamoff off, ios: : seek_dir dir); streampos tellp(); Первый аргумент – смещение позиции в байтах. Второй аргумент определяет, откуда отсчитывается смещение; он может принимать одно из трех значений: ios: : beg смещение от начала файла ios: : cur смещение от текущей позиции ios: : end смещение от конца файла
Двоичные файлы Чтение из файла производится методами read или get: istream& read(char* pch, int n. Count); istream& get(char& rch); l Метод read вводит указанное количество байтов (n. Count) в память, начиная с адреса pch. Метод get вводит один байт. l Так же, как и для вывода, текущую позицию ввода можно изменить с помощью метода seekg() l Получить текущую позицию можно с помощью метода tellg() l По завершении выполнения операций с файлами надо закрыть файлы с l помощью close или просто уничтожить объект . #include
Вывод/ввод массивов и структур #include
Проверка ошибок файловых операций #include
#include
Перегрузка файловых потоков для пользовательских типов #include
Строковые потоки l Класс strstream Функция split_numbers выделяет числа из строки, состоящей из нескольких чисел, разделенных пробелом, и печатает их по одному на строке. #include


