Какой оператор осуществляет вывод потока данных в файл

Обновлено: 02.07.2024

Текстовыми называют файлы, состоящие из любых символов. Они организуются по строкам, каждая из которых заканчивается символом "конец строки". Конец самого файла обозначается символом " конец файла ". При записи информации в текстовый файл , просмотреть который можно с помощью любого текстового редактора, все данные преобразуются к символьному типу и хранятся в символьном виде.

Для работы с файлами используются специальные типы данных, называемые потоками 4 Вообще говоря, потоки являются классами, которым будет посвящена специальная глава. . Поток ifstream служит для работы с файлами в режиме чтения. Поток ofstream служит для работы с файлами в режиме записи. Для работы с файлами в режиме как чтения, так и записи служит поток iofstream .

В программах на C++ при работе с текстовыми файлами необходимо подключать библиотеки iostream и fstream .

Для того, чтобы записать данные в текстовый файл , необходимо:

  1. Описать переменную типа ofstream.
  2. Открыть файл с помощью функции open.
  3. Вывести информацию в файл.
  4. Закрыть файл.

Для того, чтобы считать данные из текстового файла, необходимо:

  1. Описать переменную типа ifstream.
  2. Открыть файл с помощью функции open.
  3. Считать информацию из файла, при считывании каждой порции данных необходимо проверять достигнут ли конец файла.
  4. Закрыть файл.

7.2.1 Запись информации в текстовый файл

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

ofstream F; 5 Далее термин "поток" будет использоваться для указания переменной, описанной как ofstream, ifstream, iofstream , а термин "файл" для указания реального файла на диске.

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

Здесь F — переменная, описанная как ofstream, file — имя файла на диске, mode — режим работы с открываемым файлом.

Файл может быть открыт в одном из следующих режимов:

  • ios::in — открыть файл в режиме чтения данных, этот режим является режимом по умолчанию для потоков ifstream;
  • ios::out — открыть файл в режиме записи данных (при этом информация в существующем файле уничтожается), этот режим является режимом по умолчанию для потоков ofstream ;
  • ios::app — открыть файл в режиме записи данных в конец файла;
  • ios::ate — передвинуться в конец уже открытого файла;
  • ios::trunc — очистить файл, это же происходит в режиме ios::out;
  • ios::nocreate — не выполнять операцию открытия файла, если он не существует 6 При открытии файла в режиме ios::in происходит как раз обратное, если файл не существует, он создаётся ;
  • ios::noreplace — не открывать существующий файл.

Параметр mode может отсутствовать, в этом случае файл открывается в режиме по умолчанию для данного потока 7 ios::in — для потоков ifstream, ios::out — для потоков ofstream . .

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

Открыть файл (в качестве примера возьмём файл abc.txt ) в режиме записи можно одним из следующих способов:

После открытия файла в режиме записи будет создан пустой файл, в который можно будет записывать информацию. Если нужно открыть файл, чтобы в него что-либо дописать, то в качестве режима следует использовать значение ios::app .

После открытия файла в режиме записи, в него можно писать точно также, как и на экран, только вместо стандартного устройства вывода cout необходимо указать имя открытого для записи файла.

Например, для записи в поток F переменной a оператор вывода будет иметь вид:

Для последовательного вывода в поток G переменных b, c и d оператор вывода станет таким:

Закрытие потока осуществляется с помощью оператора:

В качестве примера рассмотрим следующую задачу.

Задача 7.1. Создать текстовый файл abc.txt и записать туда n вещественных чисел.

Текст программы с комментариями:

Обратите внимание, что в текстовый файл записываются не только вещественные числа, но и символы табуляции. Таким образом, в конце файла после последнего числа находится символ табуляции. По этой причине может возникнуть проблема при чтении информации (п. 7.2.2), так как символ табуляции будет интерпретирован как вещественное число. Чтобы этого избежать в программе была применена следующая конструкция:

Здесь реализована проверка ввода последнего числа. После него символ табуляции отсутствует.

В результате работы программы будет создан текстовый файл abc.txt , который можно просмотреть средствами обычного текстового редактора (рис. 7.1,рис. 7.2).

7.2.2 Чтение информации из текстового файла

Процесс работы программы к задаче 7.1. Ввод исходных данных.

Текстовый файл abc.txt, созданный программой к задаче 7.1.

Для того, чтобы прочитать информацию из текстового файла, необходимо описать переменную типа ifstream . После этого файл необходимо открыть для чтения с помощью оператора open . Если переменную назвать F , то первые два оператора будут такими:

8 Указание режима ios::in можно, конечно, опустить, ведь для потока ifstream значение ios::in является значением по умолчанию, тогда оператор open можно будет записать так F.open("abc.txt");

После открытия файла в режиме чтения, из него можно считывать информацию точно так же, как и с клавиатуры, только вместо стандартного устройства ввода cin необходимо указать имя потока, из которого будет происходить чтение данных.

Например, для чтения из потока F в переменную a оператор ввода будет иметь вид:

Для последовательного ввода из потока G в переменные b, с и d оператор ввода станет таким:

Два числа в текстовом файле считаются разделёнными, если между ними есть хотя бы один из символов: пробел, табуляция, символ конца строки.

Хорошо, если программисту заранее известно, сколько и каких значений хранится в текстовом файле. Однако часто просто известен тип значений, хранящихся в файле, при этом количество значений в файле может быть различным. При решении подобной проблемы необходимо считывать значения из файла по одному, а перед каждым считыванием проверять, достигнут ли конец файла. Для проверки, достигнут или нет конец файла, служит функция

Здесь F — имя потока, функция возвращает логическое значение: true — если достигнут конец файла, если не достигнут функция возвращает значение false .

Следовательно, цикл для чтения содержимого всего файла можно записать так.

Рассмотрим следующую задачу.

abc.txt

Задача 7.2. В текстовом файле хранятся вещественные числа (рис. 7.2), вывести их на экран и вычислить их количество.

Текст программы с комментариями приведён ниже.

Результат работы программы к задаче 7.2:

Программа работает корректно, если текстовый файл abc.txt был создан с помощью программы к задаче 7.1. Предположим, что файл создавался в текстовом редакторе, и пользователь ввёл после последней цифры символ пробела, табуляции или перехода на новую строку. Тогда результат будет таким:

Происходит это потому, что после чтения последней цифры из потока конец файла не достигнут, оператор цикла выполняется ещё один раз, значение переменной увеличивается на единицу, а так как значение переменной не изменилось, то выводится повторно. Один из способов решения данной проблемы может быть таким:

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

Существует возможность открывать файл с данными таким образом, чтобы в него можно было дописывать информацию. Рассмотрим эту возможность на примере решения следующей задачи.

abc.txt

Задача 7.3. В файле (рис. 7.2) хранится массив вещественных чисел, дописать в файл этот же массив, упорядочив его по возрастанию.

Алгоритм решения задачи очень простой. Считываем в массив данные из текстового файла, упорядочиваем массив, дописываем его в этот же файл.

Для чтения данных из файла описываем поток ifstream , открываем его в режиме чтения и последовательно, пока не достигнем конца файла, считываем все элементы в массив. Сортировку проведём методом пузырька. Обратите внимание, что поток нужно открыть так, чтобы была возможность дописать в конец файла упорядоченный массив.

Для вывода данных используеся оператор . Этот опрератор определен для всех встроенных типов C++ и некоторых классов, входящих в стандартную библиотеку. Для вывода перевода строки можно использовать специальный объект endl .

Примеры использования потока вывода:

Также оператор можно использовать и со своими классами, определив для них перегруженный оператор. Например, для структуры Book перегруженный оператор может выглядеть так:

Некоторые методы класса ostream:

  • put(char c) - записать символ с в поток
  • write(const char* s, streamsize n) - записать первые n элементов массива s в поток (streamsize представляет целое число со знаком, например, int)
  • flush() - записать значение из буфера
  • close() - закрытие потока

Потоки ввода (istream)

Для ввода используется оператор >> . Он также определен для всех встроенных типов и некоторых классов стандартной библиотеки.

Оператор >> также можно определить для своих классов:

Некоторые методы класса istream:

  • get() - считать следующий символ
  • get(char *buf, streamsize n) - считать максимум n-1 символ и поместить в массив buf
  • get(char *buf, streamsize n, char delim) - считывание символов до символа-разделителя delim (разделитель не считывается и остается в потоке)
  • getline(char *buf, streamsize n)
  • getline(char *buf, streamsize n, char delim)
  • peek() - считывает следующий символ, но оставляет его в потоке
  • ignore(streamsize n = 1, int delim = EOF) - извлекает символы из потока до тех пор, пока их число меньше n или пока не встретился символ delim
  • putback(char c) - добавляет символ с в текущую позицию потока
  • unget() - возвращает последний считанный символ в поток

Форматирование

Для управления форматом вывода можно устанавливать специальные флаги потока методом setf(ios_base::fmtflags f) . Но удобнее пользоваться манипуляторами - специальными функциями, реализованными в заголочных файлах , (они по умолчанию включены в ) и .

Основные манипуляторы ввода/вывода:

  • boolalpha - стороковое представление логических значений
  • noboolalpha - числовое представление логических значений
  • showbase - включает вывод 0 перед восьмеричными и 0x перед шестнадцатеричными числами
  • noshowbase - выключает вывод 0 и 0x
  • dec - вывод чисел в десятичной системе счисления
  • oct - в восьмеричной
  • hex - в шестнадцатеричной
  • uppercase - заглавные буквы в записи шестнадцатеричных чисел и чисел с плавающей запятой в научной записи
  • nouppercase - строчные буквы в записи чисел
  • skipws - пропуск символов-разделителей ( ' ', '\t', '\n', и т.п. )
  • noskipws - выключение пропуска разделителей
  • setw(int n) - определяет минимальное количество символов, которые выведутся следующей операцией вывода
  • setfill(char c) - символ-заполнитель
  • left - выравнивание поля по левому краю
  • right - выравнивание поля по правому краю
  • internal - выравнивание поля по ширине
  • scientific - научная запись для чисел с плавающей запятой
  • fixed - фиксированная точность для чисел с плавающей запятой
  • setprecision - точность вывода чисел (по умолчанию равна 6)
  • endl - запись \n и очистка буфера
  • ends - запись \0
  • flush - очистка буфера потока
  • ws - прочитать и проигнорировать символы-разделители

Сотояние потока

Каждый поток istream или ostream имеет связанное с ним состояние.

Методы проверки состояния:

  • good() - можно выполнить следующую операцию
  • eof() - конец потока
  • fail() - следующая операция не выполнится
  • bad() - поток испорчен

Стандартные потоки - iostream

Для реализации стандартного ввода/вывода в библиотеку C++ включен заголовочный файл iostream , содержащий следующие предопределенные объекты потоков:

  • cin - стандартный поток ввода (соответствует потоку C stdin)
  • cout - стандартный поток вывода (соответствует stdout)
  • cerr - стандартный поток вывода ошибок (соответствует stderr)
  • clog - стандартный поток вывода журнала (соответствует stderr)

Файловые потоки - fstream

Файловые потоки расположены в заголовочном файле . ifstream - поток ввода, ofstream - поток вывода.

Имя файла передается потоку либо в конструкторе, либо через вызов метода open .

Чтение данных из потока называется извлечением, а запись в поток- помещением.

Иерархия потоков


Потоки ввода/вывода

В языке С++ с каждым устройством ассоциируется поток ввода/вывода:

  • cin - стандартный поток ввода (клавиатура)
  • cout - стандартный поток вывода (терминал)
  • cerr - стандартный поток ошибок.

При работе с потоками происходит автоматический перевод из типа данных в строку для вывода на экран и из строки в числовой тип при вводе.

Для работы со стандартными потоками подключается заголовочный файл iostream

Потоки ввода вывода

Данные разных типов можно смешивать:

Ввод/вывод строк

При вводе строк извлечение происходит до ближайшего пробела (или другого стандартного разделителя)

Для ввода строк целиком используются методы потоков get и getline.

В следующем примере демонстрируется ввод строк целиком

Ввод вывод строк

Для обеспечения безопасного ввода может применяться манипулятор setw:

Циклический ввод-вывод

Данный цикл позволяет ввести строку, а потом очищает ее от разделителей при выводе.

Циклическии ввод-вывод

Здесь осуществляется посимвольный ввод/вывод вместе с разделителями

Форматирование

С помощью механизма флагов можно управлять параметрами вывода данных на консоль.

Устанавливается значение флага через метод setf, а снимается с помощью unsetf.

Вывод логических величин в текстовом виде:

Основные флаги форматирования:

  • left - левое выравнивание
  • right - правое выравнивание
  • boolalpha - вывод логических значений в текстовом виде
  • dec - основание системы счисления 10
  • oct - основание системы счисления 8
  • hex - основание системы счисления 16
  • showbase - выводить индикатор системы счисления
  • showpos - показывать + для положительных чисел
  • scientific - экспонециальная форма вещественного числа
  • fixed - фиксированная форма вещественного числа

Помимо флагов, изменяющих состояние потока можно использовать манипуляторы.

Идея манипуляторов состоит в том, что их можно помещать в поток вместе с данными.

Многие манипуляторы повторяют названиями флаги.

Для работы с манипуляторами нужно подключить заголовочный файл iomanip.

  • setw() - установить ширину поля
  • setprecision() - количество цифр в дробной части
  • left - выравнивание по левой границе
  • right - выравнивание по правой границе
  • boolalpha - вывод логических значений в текстовом виде
  • nobool alpha - вывод логических значений в числовом виде
  • dec - десятичная система счисления
  • oct - восьмеричная система счисления
  • hex - шестнадцатиричная система счисления
  • showbase - показывать признак системы счисления
  • noshowbase - не показывать признак системы счисления
  • showpos - выводить + для положительных чисел
  • noshowpos - не выводить + для положительных чисел
  • sceintific - экспоненциальная форма для вещественных чисел
  • fixed - фиксированная форма
  • setfill() - установить символ заполнитель пустых элементов поля

2 Файловые потоки

Файлы данных

Под файлами данных будем понимать хранилища информации в энергонезависимой памяти компьютера. Каждый файл имеет путевое имя в файловой системе, права на чтение/запись, размер.

Файлы данных используются для хранения информации в перерывах между сеансами работы пользователей.

Для работы с файлами данных в С++ используются специальные файловые потоки

Порядок работы с файлом

При работе с файлом придерживаются следующей последовательности:

  1. Открытие файла (создание потокового объекта).
  2. Проверка результата открытия.
  3. Чтение/запись данных.
  4. Закрытие файла.

Иногда после открытия требуется позиционирование, то есть перемещение к нужной позиции внутри открытого файла.

Открытие файла

Для работы с файлами мы подключаем заголовочный файл fstream

Заголовочный файл определяет несколько потоков для работы с файлами

  • ifstream - для чтения данных из файла
  • ofstream - для записи данных в файл
  • fstream - для записи и чтения данных

В следующем примере файл 1.txt открывается для чтения, а 2.txt - для записи:

Открывать файлы можно другим способом.

Сначала создаются объекты файловых потоков, а затем вызывается метод open() файлового потока:

У данного способа есть два преимущества:

  • Можно снова открыть тот же самый файл после закрытия не создавая новый потоковый объект.
  • Один и тот же потоковый объект может применяться для открытия нескольких файлов (последовательно).

При открытии файла необходимо указать его путевое имя. Путевое имя может быть относительным и абсолютным.

Относительное имя

Короткое имя файла в текущем каталоге

Абсолютное (полное) имя

Путевое имя файла в операционной системе

Пример с использованием полного имени в ОС Windows:

Следует обратить внимание на то, что обратный слэш в строковых константах должен удваиваться.

Пример с использованием полного имени в ОС Unix:

У файловых объектов есть функция fail(), которая в случае ошибки открытия возвращает истинное значение.

При открытии на чтение, входной файл должен существовать.

При открытии на запись, файлу существовать необязательно, поскольку он все равно будет создан.

Закрытие файла

Для закрытия файла используется функция close().

При закрытии файла, в который производилась запись, все данные будут записаны на диск.

Чтение данных

Чтение данных из файла может осуществляться разными способами:

  • посимвольно (побайтно);
  • поэлементно (до пробела или перевода строки);
  • построчно;
  • поблочно.

Посимвольное чтение

В следующем примере файл читается посимвольно.

Построчное чтение

В следующем примере файл читается построчно.

Еще один пример функции, читающей файл построчно:

Поэлементное чтение

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

Поблочное чтение

Поблочное чтение означает, что из файла читается блок данных определенного размера.

В следующем примере мы читаем из файла структуру BOOK:

После чтения, позиция внутри файла сдвигается на размер структуры BOOK.

Запись в файлы

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

Операции get соответствует put, операции read - write.

В следующем примере показано использование операции помещения информации в поток:

В файл 2.txt помещается 10 строк с приветствием и его порядковым номером. При выводе в файл числовых значений они будут преобразованы в строки.

Запись и чтение

Файл можно открыть для записи и чтения:

С каждой операцией записи/чтения позиция внутри файла сдвигается на определенное число байт, равное размеру записанных или прочитанных данных. Для изменения текущей позиции надо использовать метод seekp().

Возможные варианты второго параметра seekp()

  1. pos::beg - начало файла
  2. pos::end - конец файла
  3. pos::cur - текущая позиция (любая)

Бинарный и текстовый режимы

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

В текстовом режиме при вводе/выводе символа перевода строки автоматически удаляется/добавляется символ возврата каретки.

Этот раздел является переводом туториала C++ Language

Примеры программ предыдущих разделов обеспечивали незначительное взаимодействие с пользователем, если оно вообще было. Они просто отображали значения на экране, но стандартная библиотека предоставляет множество дополнительных способов взаимодействия с пользователем через функции ввода / вывода. В этом разделе будет представлено краткое введение в некоторые из наиболее полезных. C++ использует удобную абстракцию, называемую потоками, для выполнения операций ввода и вывода на последовательных носителях, таких как экран, клавиатура или файл.

Поток - это объект, и программа может вставлять или извлекать символы в / из него. Нет необходимости знать подробности о внутреннем строении потока, или о любых его внутренних спецификациях. Все, что нам нужно знать, это то, что потоки являются источником / адресатом символов и что эти символы предоставляются / принимаются последовательно (то есть один за другим).

Стандартная библиотека определяет несколько потоков, которые могут быть использованы для доступа к стандартным объектам из окружения во время работы программы:

поток описание
cin стандартный поток ввода
cout стандартный поток вывода
cerr стандартный поток ошибок (вывод)
clog стандартный поток журналирования (вывод)

Стандартный вывод (cout)

В большинстве программных сред стандартный поток вывода по умолчанию выводится на экран, объектом C++ для доступа к нему является cout.

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

В большинстве программных сред стандартным вводом по умолчанию является клавиатура, а объект потока C++, определенный для доступа к нему, - cin.

Для операций форматированного ввода cin используется вместе с операцией извлечения, который записывается как >> (т.е. два знака "больше"). Далее следует переменная, в которой должны хранится извлеченные данные. Например:

В первом выражении объявляется переменная age типа int, а во втором из cin извлекается значение, которое будет в ней храниться. Эта операция приводит к ожиданию ввода из cin. Обычно это означает, что программа будет ожидать, пока пользователь введет некоторую последовательность с клавиатуры. В этом случае стоит отметить, что введенные символы будут переданы программе после нажатия клавиши ENTER (или RETURN). При достижении операции извлечения из cin, программа будет ждать настолько долго, насколько это необходимо, пока не будет произведен ввод.

Операция извлечения из cin использует тип переменной после >> для определения того, как интерпретировать символы из ввода; если это число, ожидаемым форматом ввода будем последовательность цифр, если строка, то последовательность символов и т.д.

Как вы видите, извлечение из cin делает задачу ввода данных из стандартного ввода довольно простой. Но этот метод имеет также большой недостаток. Что произойдет в примере выше, если пользователь введет что-то, что не может быть интерпретировано как целое число? В этом случае операция извлечения завершится неудачно. И это, по умолчанию, позволяет программе продолжить работу, не устанавливая значение переменной i, что приведет к неопределенному результату, если значение i используется позже.

Это плохое поведение программы. Большинство программ должны вести себя так, как ожидается, независимо от того, что вводит пользователь, занимаясь обработкой неправильных значений. Только очень простые программы могут зависеть от значений, введенных из cin, без соответствующей проверки. Немного позже мы увидим, как stringstream можно использовать для контроля за пользовательским вводом.

Извлечением из cin можно запрашивать более одного элемента в одном выражении:

В обоих случаях от пользователя требуется ввод двух значений: одно для переменной a, а другое для переменной b. Для разделения двух последовательных операций ввода используется любой тип разделителей. Это могут быть пробелы, символы табуляции или новой строки.

cin и строки

Оператор извлечения может быть применен к cin для извлечения строк символов так же, как и для фундаментальных типов данных:

Однако извлечение из cin считает разделители (пробелы, символы табуляции и новой строки. ) окончанием извлекаемого значения. Таким образом, извлечение строки означает извлечение одного слова, а не фразы или предложения.

Для получения из cin целой строки имеется функция getline, которая принимает поток (cin) первым аргументом и строковую переменную вторым. Например:

Обратите внимание на то, что в обоих вызовах getline мы используем один и тот же идентификатор (mystr). Во втором случае программа просто замещает предыдущее содержимое новым, которое введено.

Стандартным поведением, которое большинство пользователей ожидают от консольной программы, это запрос ввода от пользователя каждый раз, пользователь заполняет поле и затем нажимает ENTER (RETURN). Поэтому, если у вас нет веской причины не делать этого, вы всегда должны использовать getline для получения ввода в консольных программах вместо извлечения из cin.

stringstream

Стандартный заголовочный файл определяет тип stringstream, который позволяет обрабатывать строку как поток, и это позволяет использовать операции вставки/извлечения в/из строки так же, как если бы она была потоком cin или cout. Эта возможность особенно полезна для преобразования строк в числовые значения и наоборот. Например, чтобы извлечь целое число из строки, мы можем написать:

Здесь объявляется переменная типа string и инициализируется значением "1204", и переменная типа int. Затем в третьей строке эта переменная используется для извлечения из потока, созданного из строки. Эта часть кода сохраняет числовое значение 1204 в переменной myint.

В этом примере мы получаем числовые значения из стандартного ввода косвенно: вместо извлечения числовых значений непосредственно из cin мы получаем строки из него в строковый объект (mystr), затем мы извлекаем значения из этой строки в переменные price и quantity. Так как это числовые значения, с ними можно производить арифметические операции, такие как умножение, для получения итоговой цены.

Используя этот подход для получения целых строк и извлечения их содержимого, мы отделяем процесс получения пользовательского ввода от его интерпретации как данных, позволяя процессу ввода быть тем, чего ожидает пользователь, и в то же время получить больше контроля над преобразованием его содержимого в полезные данные.

Читайте также: