л_20_21_ввод_вывод.ppt
- Количество слайдов: 55
Стрикелева Л. В. Программирование Лекция 20 -21 Основы системы ввода-вывода
Основы системы ввода-вывода Средства ввода-вывода С были новаторскими по отношению к другим языкам программирования: • они были отделены от языка программирования и вынесены в отдельную стандартную библиотеку, получившую название
Основы системы ввода-вывода Главное достоинство системы ввода-вывода С++: возможность перегружаться для новых классов, что позволяет легко встраивать в систему ввода-вывода С++ новые создаваемые типы данных. Система ввода-вывода С++ состоит из двух уровней: логического и физического. Физический уровень – это есть либо внешний файл, либо область памяти, либо устройство компьютера, имеющее свое фиксированное имя. Логический уровень – это «логическое устройство» – поток – структура данных, существующая в представлении программиста при написании программы (представляется в программе потоковой переменной определенного типа). Поток (потоковая переменная) после создания может быть использован как средство общения с любым физическим файлом или устройством. Л. В. Стрикелева Программирование 3
Основы системы ввода-вывода Принципы организации вводавывода данных в С++: • периферийные устройства ввода-вывода интерпретируются как специальные файлы, поэтому дисковые файлы и устройства ввода-вывода не различаются, и подход к организации обмена данными с ними одинаков; • файлы интерпретируются как потоки данных: данные читаются из файла и записываются в файл потоком (побайтно, посимвольно); поток с точки зрения программы не зависит от конкретных устройств (файл на диске, экран, клавиатура); • средства ввода-вывода обеспечивают программиста механизмом для извлечения данных из потоков и для включения данных в потоки; операция извлечения из потока >>; операция вывода в поток <<; • выполнение операции «извлечение из потока» заключается в преобразовании последовательности символов потока в значение типизированного объекта; внешнее представление данных – символьное изображение; внутреннее представление данных – последовательности двоичных кодов (регламентированной для каждого типа длины). • операция «включение в поток» предполагает обратное преобразование – типизированное значение (int, float, char, …. . ) трансформируется в последовательность символов потока; при выводе на экран идет преобразование двоичных кодов в символы алфавита, изображаемые на внешнем устройстве. Л. В. Стрикелева Программирование 4
Основы системы ввода-вывода Принципы организации вводавывода данных в С++: • задача программиста при вводе-выводе с помощью потоков – установить соответствие между участвующими в обмене типизированными объектами и последовательностью байтов потока, в которой отсутствует всякая информация о типах передаваемой информации; • в соответствии с особенностями «устройства» , к которому «присоединен» поток, их делят на стандартные, файлы и строковые; • стандартные потоки соответствуют передаче данных «от клавиатуры» и «к экрану» ; бывают только однонаправленными: информация либо только читается из потока, либо только пишется в поток; • если символы потока размещаются на внешнем носителе данных (диске и т. д. ) – это файловый поток; • если символы потока в совокупности образуют символьный массив (строку) в основной памяти, то это строковый поток; файловые и строковые потоки могут быть и двунаправленными: из потока можно вводить информацию и в тот же поток – выводить; • с потоком связывается внутренний указатель, значение которого задает позицию для выполнения следующей операции чтения или записи; • каждый поток (в том числе и стандартный) в каждый момент времени находится в некотором состоянии; эти состояния называются good, eof , bad, fail, hardfail; Л. В. Стрикелева Программирование 5
Основы системы ввода-вывода Потоки подразделяют на: • входные (информация считывается из потока) и выходные (данные выводятся в поток); • буферизуемые (данные помещаются в буфер потока, перед тем как они будут переданы внешнему устройству (при выводе) или перед тем, как они будут переданы в область памяти выполняемой программы (при вводе)) и небуферизуемые; форматируемые и неформатируемые: форматированный ввод-вывод : при вводе выполняется преобразование данных из внешнего представления (символьного) в двоичное (внутреннее) представление, а при выводе – наоборот; форматирование всегда выполняется для стандартных потоков; поток, созданный с помощью оператора <<, представляет поток с отформатированным текстом, и наоборот, поток, содержимое которого считывается с помощью оператора >>, должен быть потоком с отформатированным текстом; неформатированный ввод-вывод сводится к пересылке некоторого числа байтов (в этом случае байт является самостоятельным элементом данных); такая пересылка данных имеет высокую скорость, однако, неудобна для программиста; числа при этом вводе-выводе сохраняются во внутреннем представлении; Л. В. Стрикелева Программирование 6
Основы системы ввода-вывода Схема организации буферизированного входного и выходного потоков Буферизированный выходной поток Передача при пустом буфере ввода Передача при заполнении буфера или по команде «пересылка буфера» Буферизированный входной поток при вводе буфер обычно заполняется при выполнении первой операции 7 ввода, но специально программировать это не требуется; Л. В. Стрикелева Программирование
Основы системы ввода-вывода Особенности наличия буфера для стандартного входного потока: • в процессе набора данных на клавиатуре они отображаются на экране и помещаются в буфер ввода (это позволяет исправлять ошибки) ; • извлечение – только после нажатия
Основы системы ввода-вывода. Стандартные потоки Потоки istream, ostream и iostream становятся доступными при включении в программу заголовка
Основы системы ввода-вывода Состояния потока Каждый поток имеет связанное с ним состояние. Состояния потока описываются в классе ios в виде перечисления enum. public: enum io_state { goodbit, // нет ошибки 0 Х 00 (значения флагов зависят от реализации) eofbit, // конец файла 0 Х 01 failbit, // последняя операция не выполнилась 0 Х 02 badbit, // попытка использования недопустимой операции 0 Х 04 hardfail // фатальная ошибка 0 Х 08 }; Флаги, определяющие результат последней операции объектом ios, содержатся в переменной state. Получить значение этой переменной можно с помощью функции int rdstate(). Кроме того, проверить состояние потока можно следующими функциями: int bad(void); // 1, badbit или hardfailint состояние eof возникает int eof(void); // 1, если eofbit int fail(void); // 1, если failbit, badbit или hardfail только при операции чтения (для cin – при нажатии Ctrl+Z; int good(void); // 1, если goodbit для файлов – при первой Функция clear(): • без аргумента – снимает флаги ошибок; попытке чтения после конца • с аргументом – устанавливает указанный флаг, файла); при этом поток например, clear(ios: : failbit). переводится в состояние fail; Л. В. Стрикелева Программирование 10
Основы системы ввода-вывода Проверка состояния потока Состояние потока можно проверить непосредственно в условии if или в цикле while: while (cin >> i) cout << i << endl; в заголовке оператора цикла неявно вызывается оператор проверки состояния потока, который возвращает true только в том случае, если операция ввода прошла успешно; Запись этого же оператора с использованием функции cin. good(): while ( (cin >> i), cin. good() ) cout << i << endl; Уточнить ошибку поможет наличие после указанного оператора цикла следующих операторов: if (cin. eof()) cout << "End of file" << endl; else if (cin. fail()) cout << "failbit set" << endl; else if (cin. bad()) cout << "badbit set" << endl; Л. В. Стрикелева Программирование 11
Основы системы ввода-вывода Проверка состояния потока if (cin. bad()) { Для продолжения ввода после анализа cin. clear(); // очищаем флаги ошибки надо очистить флаги функцией cin >> i ; // пытаемся повторить ввод clear(), аргументом которой по умолчанию является состояние потока goodbit: } _________________________________ int main() { int i; while (true) //бесконечный цикл { cout << "input int" << endl; cin >> i; if (cin. good()) //если нет ошибок при вводе { //…… break; //выход из бесконечного цикла } cin. clear(); //если ошибка при вводе, очищаем флаги cout << "error" << endl; cin. ignore(10, 'n'); //функция извлекает оставшиеся символы из потока, //ее параметры: //10 - количество удаляемых символов (1–по умолчанию), // ’n’ – символ-ограничитель – тоже удаляется из потока, // по умолчанию символ-ограничитель – конец файла } Л. В. Стрикелева cout << i << endl; _getch(); return 0; } Программирование 12
Основы системы ввода-вывода Стандартные потоки Форматированный ввод-вывод реализуется через перегруженные операции. Для перегрузки операций (т. е. для распространения области действия стандартных операций на новые пользовательские типы) используется специальная функция-операция, имеющая формат: тип_возвращаемого_значения operator знак_операции (спецификация_параметоров_ функции_операции) {операторы_тела_функции_операции } В классе ostream, например, определены перегруженные операции: ostream& operator<< (ostream&, short); //для целых ostream& operator<< (ostream&, int); ostream& operator<< (ostream&, long); ostream& operator<< (ostream&, char); //для символов ostream& operator<< (ostream&, double); //для вещественных ostream& operator<< (ostream&, const char *); //для строк и т. д. Для оператора cout << k; компилятор выполнит: 1. Определит, что левый аргумент (объект cout) имеет тип ostream, а правый k – тип int; 2. В классе ostream объекта cout найдет прототип метода (функции_операции) ostream& operator<<(ostream&, int); 3. для объекта cout вызовет этот метод: Для операций >> аналогично: istream& operator<< (istream&, short); и т. д. Л. В. Стрикелева Программирование cout. operator<<(k); 13
Основы системы ввода-вывода. Стандартные потоки Пример перегрузки операторов ввода/вывода структурной переменной в стандартный поток. Перегрузка выполняется внешними функциями struct complex { float re, im; }; //определение структурного типа ostream& operator <<(ostream& os, const complex& cc ); //прототип функции перегрузки вывода istream& operator >>( istream& is, complex& cc ); //прототип функции перегрузки ввода int main() {complex c 1, c 2; //определение комплексных чисел cin >>c 1; //ввод чисел istream& operator>> (istream&, complex& cc); cin >> c 2; //operator>> (cin, с2); cout << c 1; //вывод чисел ostream& operator<< (ostream&, const complex& cc); cout << c 2; // operator<< (cout, с2); _getch(); return 0; } ostream& operator << (ostream& os, const complex& cc ) //внешняя функция { os << cc. re << " " << cc. im << endl; //поля в struct открыты return os; } istream& operator >>( istream& is, complex& cc ) //внешняя функция { is >> cc. re >> cc. im ; return is; } Л. В. Стрикелева Программирование 14
Основы системы ввода-вывода. Стандартные потоки При вводе: • вся строка помещается в буфер ввода; • ввод завершается нажатием
Основы системы ввода-вывода. Стандартные потоки При вводе: • ввод перечислимого типа как целого по умолчанию не работает; для каждого нового перечислимого типа необходимо писать собственные операции вводавывода; • ввод символа (даже единственного) заканчивается нажатием клавиши
Основы системы ввода-вывода. Стандартные потоки При выводе: • целые числа выводятся в десятичной системе счисления; 16 -ичная константа 0 x. FFFF будет показана как десятичное число 65535; • для дробного числа (независимо от типа) выводится только 6 цифр после запятой (например, число 7. 123456789 выводится как 7. 123457, а число 123456789. 15 – как 123456789. 150000 или 1. 234568 е+008; • указатели по умолчанию выводятся в 16 -ичной с/с, независимо от типа; исключение – указатель на тип char: выводится как строка символов, на которую он указывает; для вывода указателя необходимо преобразование типа к типу void* (char *s=”aaaaan”; cout << s << “ “ << static_cast
Основы системы ввода-вывода. Стандартные потоки При выводе: • при выводе строки из памяти в выходной поток переносятся все символы до ‘ ’; Операция << работает и с символьными массивами и со строками типа string (string s 3 = “aaaaan”; cout << s 3; ); вывести строку (кроме переменных типа string) можно и методом write() (char *s 1=”bbbbb”; cout. write(s 1, strlen(s 1)); • при выводе выражений необходимо учитывать приоритет операций; оператор << изначально является операцией сдвига влево и имеет свой приоритет (например, cout << d = f << ‘n’; интерпретируется как (cout << d) = (f << ‘n’); и вызовет ошибку трансляции; исправление: cout << (d=f) << ‘n’; ) int i; cin >> i; cout << i <
Основы системы ввода-вывода Иерархия шаблонов потоковых классов basic_ios<> – шаблон базовых потоковых классов; ios – его специализация для данных типа char. basic_istream<> – шаблон классов входных потоков; istream – его специализация для входных потоков, выполняющих посимвольные обмены. Каждый потоковый класс поддерживает буферный объект, который предоставляет память для передаваемых данных basic_istream<> ios_base basic_ostream<> – шаблон классов выходных потоков; ostream – его специализация для выходных потоков, выполняющих посимвольные обмены. basic_iostream<> – шаблон классов двунаправленных потоков; iostream – его специализация для двунаправленных потоков, выполняющих посимвольные обмены basic_ios<> constreambuf basic_ostream<> basic_ifstream<> basic_istringstream<> Л. В. Стрикелева Программирование basic_fstream<> basic_stringstream<> basic_ofstream<> basic_ostringstream<> 19
Основы системы ввода-вывода. Стандартные потоки Для влияния на форму выводимой или вводимой информации можно использовать флаги форматирования. рассматриваемые как компоненты класса ios. Флаги форматирования реализованы в виде отдельных фиксированных битов переменной представления флагов флаг назначение ios: : boolalpha представление логических значений не в числовом, а в символьном виде (true и false) десятичная система счисления (установка по умолчанию) формат вещественных чисел с фиксированной точкой шестнадцатеричная система счисления символ-заполнитель пустых позиций помещается между символом знака (или символом основания системы счисления) и числовым значением выравнивание влево выводимого значения (используется символ заполнения – по умолчанию «пробел» ) выводимые числа форматируются как восьмеричные выравнивание вправо выводимого значения – это установка по умолчанию (используется символ заполнения ) формат вещественных чисел в экспоненциальной форме 20 (научный формат) ios: : dec ios: : fixed ios: : hex ios: : internal ios: : left ios: : oct ios: : right ios: : scientific Л. В. Стрикелева Программирование
Основы системы ввода-вывода. Стандартные потоки флаг назначение ios: : showbase вывод основания системы счисления (0 – для восьмеричной, 0 х – для шестнадцатеричной) для вещественных чисел выводить десятичную точку и следующие за ней нули выводить знак положительного числа при чтении данных из входного потока игнорировать начальные пробельные символы очищать все потоки (выгружать содержимое буфера) после каждого ввода или вывода при выводе использовать символы верхнего регистра полезные значения битовой маски ios: : showpoint ios: : showpos ios: : skipws ios: : unitbuf ios: : uppercase ios: : adjustfield ios: : basefield ios: : floatfield маска для битов флага «дополнение» internal | left | right (внутри, слева, справа) маска для битов флага «основание системы счисления» dec|hex|oct (десятичная, шестнадцатеричная, восьмеричная) маска для битов флага «формат с плавающей точкой» fixed | scientific (фиксированный, научный) Проверить значения любых флагов, установить или сбросить их позволяют методы класса ios, доступные через объекты cin и cout. Л. В. Стрикелева Программирование 21
Основы системы ввода-вывода Стандартные потоки Методы работы с флагами и форматирования данных: функция-член назначение flags() flags(флаги) возвращает текущую комбинацию флагов формата или устанавливает новую setf(флаги) setf(флаги, маска) возвращает текущую комбинацию флагов формата или устанавливает новую unsetf сбрасывает флаги формата width(w) w= width(); определяет минимальную ширину форматируемого поля и возвращает текущую минимальную ширину fill(ch); ch=fill(); устанавливает или читает символ-заполнитель precision(P) P= precision(); число цифр, задействованных в форматируемых числовых величинах cout. flags (ios: : hex | ios: : uppercase); cout << 15 << 'n'; //выводит F cout. flags (ios: : oct | ios: : showbase); cout << 8 << 'n'; //выводит 010 cout. flags (ios: : hex | ios: : uppercase| ios: : showbase ); cout << 15 << 'n'; //выводит 0 XF Л. В. Стрикелева Программирование 22
Основы системы ввода-вывода Стандартные потоки cout. setf (ios: : hex, ios: : basefield); //установить 16 с/с, перед этим сбросить флаг // «основание с/с» cout. setf (ios: : uppercase); примеры: cout << 15 << 'n'; //выводит F cout. setf (ios: : showbase); cout. setf (ios: : oct, ios: : basefield); //установить 8 с/с, перед этим сбросить флаг // «основание с/с» cout << 8 << 'n'; //выводит 010 i. Flags= cout. setf(ios: : fixed, ios: : floatfield); // сбросить флаг «формат с плавающей точкой» , // установить fixed и вернуть текущее значение формата if (i. Flags & ios: : dec) cout << "integer output uses base 10n"; else if (i. Flags & ios: : hex) cout << "integer output uses base 16n"; else cout << "integer output uses base 8n"; // integer output uses base 8 cout. flags (ios: : hex | ios: : uppercase | ios: : showbase); cout <<15 << 'n'; //выводит 0 ХF cout. unsetf ( ios: : uppercase); //устанавливает флаг верхнего регистра «по умолчанию» cout <<15 << 'n'; //выводит 0 хf 23 Л. В. Стрикелева Программирование
Основы системы ввода-вывода Стандартные потоки Примеры : cout. width (4); //устанавливает ширину в 4 знака только для одного вывода cout <<15 << “n”; //выводит | 15 с двумя ведущими пробелами cout <<15 << “n”; //выводит |15 без ведущих пробелов int i, Num=255; for (i=5; i<20; i+=5; { cout <<”Number is “; cout. width(i); cout << Num << “n”; } Влияет только на ширину следующей операции вывода Number is 255 Number is 255 cout. fill (‘^’); //устанавливает ‘^’ в качестве символа-заполнителя cout. width(6); cout <<15 << “n”; //выводит ^^^^15 cout << cout. fill()<< “n”; // выводит ‘^’ в качестве текущего символа-заполнителя int Num=255; cout. fill (‘ 0’); //устанавливает ‘ 0’ в качестве нового символа-заполнителя cout. width(10); cout <
Основы системы ввода-вывода Стандартные потоки Примеры: cout. precision (3); cout <<20. 1 << “n”; //выводит 20. 100 cout << cout. precision()<< “n”; // выводит 3 в качестве текущего значения double f. X=355. 678; cout. flags (ios: : fixed); cout. precision (1); cout << “Number = “ << f. X << “(precision is “ << cout. precision() << “)n”; // выводит Number =355. 7 (precision is 1) cout. precision (3); cout << “Number = “ << f. X << “(precision is “ << cout. precision() << “)n”; //выводит Number =355. 678 (precision is 3) cout. flags (ios: : scientific); cout. precision (1); cout << “Number = “ << f. X << “(precision is “ << cout. precision() << “)n”; // выводит Number =3. 6 e+002 (precision is 1) cout. precision (3); cout << “Number = “ << f. X << “(precision is “ << cout. precision() << “)n”; // выводит Number =3. 557 e+002 (precision is 3) cout. precision (5); cout << “Number = “ << f. X << “(precision is “ << cout. precision() << “)n”; // выводит Number =3. 55678 e+002 (precision is 5) Л. В. Стрикелева Программирование 25
Основы системы ввода-вывода Стандартные потоки манипуляторы с параметрами Особенность манипуляторов и их отличие от обычных функций-членов состоит в том, что их имена (без параметров) и вызовы (с параметрами) можно использовать в качестве правого операнда для операций обмена << или >>. В качестве левого операнда в этом выражении, как обычно, используется поток (объект, представляющий поток), и именно на этот поток оказывает влияние манипулятор назначение setw(int n. Width=0) устанавливает минимальную ширину следующего поля (0 – по умолчанию) setbase (int n. Base=10) устанавливает основание системы счисления (10 – по умолчанию) setfill (char c. Fill=‘ ‘) устанавливает символ-заполнитель (пробел– по умолчанию) setprecision (int n. Prec=6) количество цифр дробной части; setiosflags (long l. Flags) устанавливает флаги формата потока resetiosflags (long l. Flags) сбрасывает флаги формата потока Л. В. Стрикелева Программирование Для работы с манипуляторами необходимо включить в программу заголовок
Основы системы ввода-вывода Манипуляторы без параметров Стандартные потоки манипулятор назначение binary устанавливает двоичный режим потокового ввода/вывода text устанавливает текстовый режим потокового ввода/вывода dec форматирует целые числа как десятичные hex форматирует целые числа как шестнадцатеричные oct форматирует целые числа как восьмеричные ws экстрактор пробельных символов endl переход на новую строку ends завершение строки нулевым символом flush закрывает буферы потока ввода/вывода Л. В. Стрикелева Программирование 27
Основы системы ввода-вывода Стандартные потоки Примеры использования манипуляторов: #include
Основы системы ввода-вывода Стандартные потоки Собственный манипулятор Можно определить собственный манипулятор (например, tab). Для этого надо просто написать функцию, которая получает и возвращает ссылку на поток: ostream& tab( ostream& os ) { return os << 't'; } cout << ‘a’ << tab << ‘b’ << endl; //a b Чтобы форматированный вывод было проще записывать, можно объединить все используемые в нем манипуляторы в одной функции. Для вывода: cout << setfill(‘-‘) << setw(10) << hex << internal << напишем функцию setfix: ostream& setfix( ostream& os ) val << endl; { os. width(10); os. fill(‘^‘); os. setf(ios: : internal, ios: : adjustfield); os. setf(ios: : hex, ios: : basefield); return os; } Тогда вывод в cout той же переменной val (имеет значение 100) в том же формате записывается значительно короче: Результат: cout << setfix << val << endl; Л. В. Стрикелева Программирование 0 X------64 0 X^^^^^^64 29
Основы системы ввода-вывода Файловые потоки • Файлы – одна из наиболее фундаментальных структур данных; посредством файлов обрабатываемые программой данные могут быть получены извне, а результаты сохранены для последующего использования разными функциями; • для управления множеством файлов в состав операционной системы входит файловая система; • имя файла в С++ обычно представляется либо константой-строкой, либо переменной – символьным массивом, в который помещается строка-имя файла; имена файлов могут содержать пробелы и символы кириллицы (нельзя использовать символы < > : “ | ); нечувствительны к регистру, однако регистр в именах сохраняется (file == FILE ==File); расширение в имени файла может отсутствовать; • полное имя файла включает и путь к файлу (идентификатор диска и имя каталога): “qwest. txt”, “c: \test\qwest. doc”, “d: /number. bin”; • файл может быть открыт для чтения (входной файл), для записи (выходной файл), для чтения и записи; • операция вывода данных в файл означает пересылку их из памяти в файл, а операция ввода – заполнение памяти данными, полученными из файла; при извлечении информации из входного файла программа должна уметь определять, когда данные закончились. Л. В. Стрикелева Программирование 30
Основы системы ввода-вывода Файловые потоки При работе с файлами программист использует классы: • ofstream (класс файлового потока вывода), • ifstream (класс файлового потока ввода), • fstream (класс двунаправленных потоков файлового ввода-вывода). Для реализации файлового ввода-вывода, необходимо включить в программу заголовок
Основы системы ввода-вывода Текстовые файлы предназначены для хранения текстовой информации: • в виде символов, представленных своими кодами (например, тексты программ); • длина файла ограничивается ёмкостью устройств внешней памяти; • в конце файла ставится признак EOF (End Of File – конец файла – ASCII-код 26). могут рассматриваться как последовательность символов, разбитая на строки: являются файлами последовательного доступа (любой элемент может быть прочитан или записан только после предшествующего); например, чтобы прочитать из файла пятый элемент (пятую строку, например), необходимо считать «впустую» четыре первых. Текстовый файл может храниться на диске или выводиться на экран. В нем можно хранить и числа: 123 456 789 0 234 567 890 1 1. 2 3. 4 5. 60 4 -100. 254 Конец файла[26] [13][10]Текстовый файл [13][10]может храниться на диске или выводиться на экран. [13][10]В нем можно хранить и числа: [13][10] 123 456 789 0[13][10]234 567 890 1[13][10]1. 2 5. 60 4[13][10]-100. 254[13][10]Конец файла[13][10][26] Л. В. Стрикелева Программирование 3. 4 32
Основы системы ввода-вывода Текстовые файлы можно рассматривать: - как последовательность строк - как последовательность символов можно создавать: с помощью тестового редактора Б Г У #13 #10 Р Ф Вся информация в текстовом файле хранится в том же формате, как если бы она находилась на экране. и в программе #13 #10 Ф Э #13 #10 #26 Числовые значения в текстовом файле имеют внешнее (текстовое) представление, разделяются пробельными символами и могут иметь разные типы. Л. В. Стрикелева Программирование 33
Основы системы ввода-вывода Текстовые файлы • позиции чтения и записи в файле определяются значениями указателей позиций записи и чтения файла; • позиционирование указателей записи и чтения выполняется либо автоматически (по порядку следования), либо за счет явного управления их положением; • данные в текстовом файле не могут быть модифицированы без риска разрушения других данных в файле; • текстовые файлы являются форматируемыми; при чтении чисел из файла, они автоматически преобразуются из внешнего (текстового) представления во внутреннее (машинное); при выводе чисел в текстовый файл, они преобразуются из внутреннего представления в символьный (текстовый) вид; при этом количество записываемых символов зависит от величины числа (например, 5, 11, -111, 25385 – целые числа типа int в машинном представлении хранятся в 4 -х байтах каждое, но при форматированном выводе в файл на диске, они занимают поля разных размеров (соответственно, 1, 2, 4, 5 символов); • в модели форматированного ввода-вывода (операции << и >>) режимы форматирования установлены по умолчанию; форматированием можно управлять явным образом, (флаги, методы, манипуляторы). Форматирование не выполняется в случае, если содержимое файла обрабатывается именно как символы и строки. текстовые файлы могут создаваться с помощью тестового Л. В. Стрикелева редактора и программно и содержать данные разных типов; Программирование 34
Основы системы ввода-вывода. Двоичные файлы хотя текстовые файлы полезны во многих случаях и содержат удобный для восприятия человека текст, у них нет гибкости неформатированных двоичных файлов; • двоичные (бинарные) файлы не являются форматируемыми (не разбиваются на строки, никаких преобразований при обмене не выполняется); пример двоичного файла – исполняемый файл с расширением exe; • элементы двоичных файлов хранятся во внутреннем представлении и поэтому должны создаваться программно; • при операции записи в двоичный файл попадает столько байтов, сколько записываемый объект занимает в памяти (для типа int – sizeof (int) байтов); • двоичные файлы могут содержать элементы разных типов, но для большей надежности их следует формировать из элементов только определенного типа; • в случае если двоичный файл представляет собой последовательность однотипных элементов, с ним можно работать и как с файлом последовательного доступа, и как с файлом прямого доступа, в котором возможен непосредственный доступ к любому из его элементов; • двоичный файл предпочтительнее текстового как в отношении надежности, так и в отношении скорости выполнения операций (даже для последовательной обработки однотипных данных); • благодаря возможности прямого доступа к своим элементам двоичные файлы представляются очень привлекательными при чередовании операций чтения и 35 Л. В. Стрикелева записи данных. Программирование
Основы системы ввода-вывода Двоичные файлы бинарные файлы могут создаваться только программно могут быть последовательностью однотипных элементов, хранимых во внутреннем представлении; char int Получить эти последовательности можно поэлементным выводом значений (в цикле) либо выводом одним оператором (как массива) с помощью функции-метода write; struct t { unsigned char a; char b; int c; } ft; Файл структур типа t struct s { int ar[3]; } fs; Файл структур типа s Л. В. Стрикелева Программирование 36
Основы системы ввода-вывода Последовательность работы с файлами • программа на С++ имеет дело с абстрактным потоком, представленным потоковой переменной, не имеющей никакого отношения к файлам на диске (ее область видимости и время жизни – в соответствии с описанием ); • чтобы работать с файлом, необходимо связать с ним переменную-поток; • общий набор процедур для работы с файлом может выглядеть так: 1 – создание файла; //представлен на диске именем и не имеет отношения к потоку 2 – создание потока; //определение переменной потокового типа 3 – открытие файла; //явно, методом open(), //неявно конструктором при создании потока 4 – «присоединение» файла к потоку; //при открытии файла 5 – обмен с файлом с помощью потока; //по умолчанию поток форматируемый и // соотносится с файлом на диске 6 – «отсоединение» потока от файла; //при закрытии файла связь разрывается, //потоковая переменная – продолжает жить 7 – закрытие файла; //явно, методом close(), неявно 8 – уничтожение потока. // деструктором при завершении программы Не все из перечисленных действий нужно явно программировать при работе со стандартной библиотекой ввода-вывода. Например, файл автоматически создается (при необходимости) и открывается при определении соответствующего объекта потокового класса, а файл закрывается при уничтожении объекта. 37 Л. В. Стрикелева Программирование
Основы системы ввода-вывода Создание файлов и потоков Создание потока, открытие (создание) файла, присоединение файла к потоку (одновременно пункты 1, 2, 3, 4): выполняются при определении потоковой переменной с явным указанием в списке параметров имени файла (остальные параметры можно не указывать, они выбираются по умолчанию): ofstream out. File (“имя_файла”); – создается выходной файловый поток с именем out. File для записи данных; поток связывается с выделяемым для него буфером и инициализируются переменные состояния потока, поток связывается с файлом; • если файл с названием имя_файла не существует, он будет создан, открыт и соединен с потоком out. File; • если файл уже существует, то предыдущий вариант будет удален и заново создан пустой файл; файл для записи с названием имя_файла разыскивается в текущем каталоге; проверка успешности открытия потока: ofstream outfile ("TEST. TXT"); //поток открыт для записи if (!out. File) {cerr <"error"; _getch(); exit(1); } ofstream ofbin ("number. bin", ios: : binary); if (!ofbin) {cerr <"error"; _getch(); exit(1); } Л. В. Стрикелева Программирование 38
Основы системы ввода-вывода Создание файлов и потоков ifstream in. File (“имя_файла”); – создается входной файловый поток с именем in. File для чтения данных; файл для чтения данных с названием имя_файла разыскивается в текущем каталоге; проверка успешности открытия потока: ifstream in. File ("d: \TEST. TXT"); //поток открыт для чтения if (!in. File) {cerr <<"error"; _getch(); exit(1); } ifstream ifbin ("TEST. bin", ios: : binary); if (!ifbin) {cerr <<"error"; _getch(); exit(1); } Режимы открытия файла ios: : in //открытие файла для ввода ios: : out //открытие файла для вывода Разрешается ios: : ate //режим поиска конца файла при его открытии задавать // операции ввода-вывода возможны в любом месте файла комбинации ios: : app //режим добавления в конец файла, открытого для вывода ios: : trunс //удаление содержимого ранее существовавшего файла ios: : _Nocreate //не создавать новый файл ios: : _Noreplace //не открывать новый файл (для существующего выходного файла, // не имеющего режимов ate или app, функция выдаст ошибку) 39 ios: : binary //открытие файла в двоичном режиме (по умолчанию – в текстовом) Л. В. Стрикелева Программирование
Основы системы ввода-вывода Работа с файлом Поток (потоковую переменную) определить независимо: ifstream infile; //определение потоковой переменной для ввода ifstream ifbin; ofstream out. File; //определение потоковой переменной out. File для вывода ofstream ofbin; fstream io. File; //определение потоковой переменной io. File для ввода и вывода Для открытия файла и связывания его с потоком служит компонентная функция open() (член каждого из названных потоковых классов). Прототипы функции для каждого класса выглядят так: void ifstream: : open (const char* file. Name, open_mode = ios: : in); void ofstream: : open (const char* file. Name, open_mode = ios: : out| ios: : trunc); void ffstream: : open (const char* file. Name, open_mode = ios: : in | ios: : out); здесь file. Name – имя файла, которое может входить в спецификатор пути; mode – режим открытия файла. out. File. open("C: \USER\RESULT. DAT"); //файл, если не существовал, будет создан, откроется только для вывода // в текстовом режиме и будет подсоединен к потоку out. File in. File. open("RESULT. DAT"); //файл, если существует, откроется только для чтения из него данных //в текстовом режиме и будет подсоединен к потоку in. File; // в противном случае – ошибка ввода Л. В. Стрикелева Программирование 40
Основы системы ввода-вывода Чтение и запись в файл Из открытого файла можно читать (или записать в него) текстовые данные с помощью операций << и >> (как и для консольного ввода-вывода, только cin и cout надо заменить потоком, который связан с файлом): ifstream in. File (“TEST. txt”); in. File >> x; //чтение в x из файла, связанного с потоковой переменной in. File. getline (line, len); //чтение в строку line из файла, связанного с потоковой переменной in. File ofstream out. File (“TEST. txt”); out. File << rand() %6 << 'n'; //вывод в файл случайного числа и символа 'n' Для неформатированного чтения и записи в потоковых классах определены методы: read() и write(): ofstream ofbin ("number. bin", ios: : binary); ofbin. write(reinterpret_cast
Основы системы ввода-вывода Проверка аварийного состояния файлового потока • с помощью перегруженной операции «operator !» : infile >> x; if (!infile) { //перегрузка операции ! аргументом-объектом //ввод завершился неудачей (установлены биты ошибок) } для выражения !infile компилятор генерирует вызов метода infile. operator!(); возвращающего true, если установлен хотя бы один бит ошибки; • с помощью перегруженной операции «operator >>» : if (!(infile >> x)) { //обработка неудачного ввода ( 0) } //в противном случае оператор возвращает ссылку на поток; while (infile >> aa[i++] ) //при вводе значений элементов массива из потока infile //цикл завершится при появлении символа, не соответствующего типу вводимой переменной, // или при создании ситуации конца файла (нажаты клавиши Ctrl+Z) состояние fail потока. • с помощью сравнения потока с 0: while (infile) { //пока нет ошибок } //при сравнении с 0, неявно вызывается компонентная функция «operator void*()» , // которая возвращает false, если установлен хотя бы один бит ошибки; Л. В. Стрикелева Программирование 42
Основы системы ввода-вывода Проверка аварийного состояния файлового потока с аргументом булевского типа : infile. getline (line, len); //чтение из потока infile в строку line while (!infile. eof()) // вызов метода eof: она возвращает true, если {cout << line << endl; // достигнут конец файла и false – в противном случае infile. getline (line, len); //чтение в строку s из потока infile состояние eof возникает только } с помощью бесконечного цикла: при первой попытке чтения последнего байта файла; while (true) { infile. getline(line, len); //чтение из потока infile в строку line if (infile. eof()) break; //если «конец файла» cout << line << endl; } с использованием явного вызова методов get или getline : int nl =0; char ch; while (infile. get(ch)) //или while (ch=infile. get() && ch!=eof) {if (ch==’n’) nl++; outfile. put(ch); } – подсчет количества символов ‘n’, которым оканчиваются вводимые строки; while (infile. getline (line, len)) { if (strstr(line, word)) {cout << “YES!” << endl; return 0; } } Л. В. Стрикелева Программирование 43
Основы системы ввода-вывода Работа с файлом Методы класса istream: для форматированного извлечения из потока данных всех основных (и перегружаемых) типов: >> (operator >>) для неформатированного чтения из потока: get() – возвращает код символа, извлеченного из потока, или EOF; get(ch) – извлекает один символ в ch и возвращает ссылку на поток; get(str) – извлекает символы в символьный массив str до ограничителя ‘n’; get(str, MAX) – извлекает до MAX числа символов в символьный массив str; get(str, DELIM) – извлекает символы в символьный массив str до указанного ограничителя (обычно ‘n’); оставляет ограничитель в потоке; get(str, MAX, DELIM) – извлекает в символьный массив str до MAX символов или до символа DELIM; оставляет ограничитель в потоке; getline(str, MAX, DELIM) – извлекает в символьный массив str до MAX символов или до символа DELIM; извлекает ограничитель из потока; ignore(MAX, DELIM) – извлекает и удаляет до MAX числа символов до ограничителя включительно (обычно ‘n’); с извлеченными данными ничего не делает; peek () – возвращает следующий символ (оставляя его в потоке) или EOF(если достигнут конец файла); peek (ch) – читает следующий символ, оставляя его в потоке; Л. В. Стрикелева Программирование 44
Основы системы ввода-вывода Работа с файлом Методы класса istream: gcount() – возвращает число символов, считанных с помощью последнего вызова функций неформатированного ввода get(), getline(), read(); putback (ch) – вставляет во входной поток символ, который становится текущим при извлечении из потока; read (str, MAX) – извлекает в символьный массив str MAX символов (или все символы до конца файла, если их меньше MAX); seekg(pos) – устанавливает расстояние (в байтах) от начала файла до файлового указателя (т. е. устанавливает текущую позицию чтения в значение pos); seekg (pos, seek_dir) – перемещает текущую позицию чтения на pos (- pos) байтов, считая от одной из трех позиций, определяемых параметром seek_dir: ios: : beg (от начала файла), ios: : cur (от текущей позиции), ios: : end (от конца файла); tellg() – возвращает позицию (в байтах) указателя файла от начала файла; tellg(pos) – возвращает позицию (в байтах) указателя файла от начала файла. Л. В. Стрикелева Программирование 45
Основы системы ввода-вывода Примеры работы с методами класса istream Работа с файлом //пример 1 char c[10], c 2; cout << "Type 'abcde': “ << endl; //abcde попадает в буфер ввода; c 2 = cin. peek( ); //определяется первый вводимый символ, он остается в буфере cin. getline( c, 9 ); //getline() вводит в символьный массив с строку abcde cout << c 2 << " " << c << endl; //вывод символа a и строки abcde // пример 2 // прочитать и вывести символы double f; ab c char ch; char c 2; d e abc while ( cin >> ch ) cout << "Type 123. 456: "; de cout << ch; cin. peek(c 2); cin >> f; // прочитать и вывести все символы cout << c 2 << " " << f << endl; //1 123. 456 char ch; ab c d e ab c while (cin. get(ch)) // пример 3 d e cout. put( ch ); char c, c 2; cout << "Type simvol a: "; // прочитать и вывести все символы cin. peek(c 2 ); char ch; ab c cin >> c; cin >> noskipws; d e ab c cout << c 2 << " " << c << endl; //a a while (cin >> c) d e cout << ch; Л. В. Стрикелева Программирование 46
Основы системы ввода-вывода Примеры работы с методами класса istream Работа с файлом const int line. Size = 1024; char ch, next, lookahead; while ( cin. get( ch )) //чтение символа из потока { switch (ch) { case '/': // это комментарий? смотрим с помощью peek() // если да, пропустить остаток строки next = cin. peek(); //просмотр следующего символа if ( next == '/' ) cin. ignore( line. Size, 'n' ); break; case '>': // проверка на лексему >>= next = cin. peek(); //просмотр следующего символа if ( next == '>' ) { lookahead = cin. get(); //чтение и сохранение этого символа next = cin. peek(); //просмотр следующего символа if ( next != '=' ) cin. putback( lookahead ); //возврат символа в поток } break; } //!!!после чтения из файла указатель файла в конце файла } //для повторного использования файла: infile. clear(); Л. В. Стрикелева Программирование //!!!очистить флаги состояния infile. seekg(0, ios: : beg); //!!!установить указатель в начало файла //теперь можно использовать повторно: 47 cout << infile. rdbuf(); //вывести буфер файлового потока !!!
Основы системы ввода-вывода Общая концепция ввода-вывода данных Методы класса ostream: для форматированного включения в поток данных всех основных (и перегружаемых) типов: << (operator<<) для неформатированного вывода в поток: put(ch) – выводит в поток один символ ch и возвращает ссылку на поток; flush() – записывает содержимое потока вывода на физическое устройство (очистка буфера); write(buf, SIZE) – записывает SIZE символов из массива buf в файл; seekp(pos) – устанавливает текущую позицию записи в значение pos относительно начала файла; seekp(pos, seek_dir) – перемещает текущую позицию файлового указателя на pos (pos) байтов, считая от одной из трех позиций, определяемых параметром seek_dir: ios: : beg (от начала файла), ios: : cur (от текущей позиции), ios: : end (от конца файла); tellр() – возвращает позицию указателя файла (в байтах). Л. В. Стрикелева Программирование 48
Основы системы ввода-вывода Примеры #include
Основы системы ввода-вывода Примеры #include
Основы системы ввода-вывода Примеры #include
Основы системы ввода-вывода Примеры #include
Основы системы ввода-вывода Замена записей в бинарном файле #include
Основы системы ввода-вывода Строковые потоки позволяют считывать и записывать информацию из областей оперативной памяти (так же, как из файла) #include
На сегодня все. До свидания До следующей встречи


