17 что такое файловые потоки ввода вывода

Обновлено: 04.07.2024

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

В С++ используется механизм потокового ввода/вывода. Поток - механизм преобразования значений различного типа в последовательность символов (вывод) и наоборот (ввод), в значение переменной.

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

  • cout - стандартный поток вывода (экран)
  • cerr - стандартный поток вывода ошибок (экран)

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

cout<<"x Data types:"<<endl; // вывод строки
cout<<"int float double navigate.html" > '
flush; // очистка буфера потока

Это лишь основные манипуляторы, которые вы можете использовать для форматирования. С остальными познакомьтесь самостоятельно:

Манипулятор Действие на поток
showbase
noshowbase
инициирует отображение основания системы счисления
showpos
noshowpos
инициирует явное отображение знака (+) для положительных значений
uppercase
nouppercase
инициирует преобразование выводимых символов в верхний регистр
showpoint
noshowpoint
инициирует отображение десятичной точки при выводе вещественных чисел
skipws
noskipws
инициирует пропуск пробельных символов при вводе
left инициирует левое выравнивание, заполнение справа
right инициирует правое выравнивание, заполнение слева
internal инициирует внутреннее заполнение (между значением и знаком или основанием системы счисления)
scientific инициирует вывод вещественных значений в научном формате (d.ddddddddE+dd)
fixed инициирует вывод вещественных значений в фиксированном формате (d.dddddd)
setbase (int base) изменяет систему счисления (10, 8, 16)
dec инициирует вывод целочисленных значений в десятичной системе счисления
oct инициирует вывод целочисленных значений в восьмеричной системе счисления
hex инициирует вывод целочисленных значений в шестнадцатеричной системе счисления
setfill (char n) задает заполняющий символ
setprecision (int n) изменяет точность выводимых значений
setw (int n) задает ширину поля вывода

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

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

void main()
ifstream inputfile("z:\data.txt"); // создается поток ввода из файла
inputfile>>x; // все то же самое что и для cin
ofstream outputfile("z:\res.txt"); // создается поток вывода в файл
outputfile<<x; // все то же самое что и для cout
>

Обратите внимание на двойной слэш \ в имени файла. Это все из-за того, что \ - экранирующий символ.

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

По умолчанию файл открываемый для вывода создается (если он создан), а если существует, то очищается. Для того чтобы открыть файл для добавления:

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

Для программиста открытый файл представляется как последовательность считываемых или записываемых данных. При открытии файла с ним связывается поток ввода-вывода . Выводимая информация записывается в поток, вводимая информация считывается из потока.

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

Файловый ввод-вывод аналогичен стандартному вводу-выводу, единственное отличие – это то, что ввод-вывод выполнятся не на экран, а в файл.

Если ввод-вывод на стандартные устройства выполняется с помощью объектов cin и cout , то для организации файлового ввода-вывода достаточно создать собственные объекты, которые можно использовать аналогично этим операторам.

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

  • создать объект класса fstream (возможно, ofstream или ifstream );
  • связать объект класса fstream с файлом, который будет использоваться для операций ввода-вывода;
  • осуществить операции ввода-вывода в файл;
  • закрыть файл.

Работа с файлами в C++

В результате будет создан файл

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

Константа Описание
ios::in открыть файл для чтения
ios::out открыть файл для записи
ios::ate при открытии переместить указатель в конец файла
ios::app открыть файл для записи в конец файла
ios::trunc удалить содержимое файла, если он существует
ios::binary открытие файла в двоичном режиме

Режимы открытия файлов можно устанавливать непосредственно при создании объекта или при вызове метода open() .

ofstream fout( "file.txt" , ios::app);
fout.open( "file.txt" , ios::app);

Режимы открытия файлов можно комбинировать с помощью поразрядной логической операции ИЛИ | , например:

ios::out | ios::in - открытие файла для записи и чтения.

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

Система ввода-вывода С++ позволяет осуществлять произвольный доступ с использованием методов seekg() и seekp() .

  • ifstream &seekg(Смещение, Позиция);
  • ofstream &seekp(Смещение, Позиция);

Смещение определяет область значений в пределах файла ( long int ).

Система ввода-вывода С++ обрабатывает два указателя, ассоциированные с каждым файлом:

  • get pointer g - определяет, где именно в файле будет производиться следующая операция ввода;
  • put pointer p - определяет, где именно в файле будет производиться следующая операция вывода.

Позиция смещения определяется как

Позиция Значение
ios::beg Начало файла
ios::cur Текущее положение
ios::end Конец файла

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

Можно определить текущую позицию файлового указателя, используя следующие функции:

  • streampos tellg() - позиция для ввода
  • streampos tellp() - позиция для вывода

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

Вторая часть программы выведет в консоль

Ещё один пример. Допустим, нам нужно заполнять таблицу

Причем каждая вновь введенная строка должна размещаться в таблице непосредственно под "шапкой".

Алгоритм решения задачи следующий:

  • формируем очередную строку для вывода
  • открываем файл для чтения, считываем из него данные и сохраняем их в массив строк
  • закрываем файл
  • открываем файл для записи
  • выводим "шапку" таблицы
  • выводим новую строку
  • выводим все сохраненные строки обратно в файл, начиная со строки после шапки
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

fstream inOut;
inOut.open( "file.txt" , ios::in); // открываем файл для ввода
// Считываем из файла имеющиеся данные
int count = 0;
while (inOut.getline(line[count], 100)) count++;
inOut.close(); // закрываем файл


Результат выполнения:


Файл данных

Полученный файл данных:

Здравствуйте Елена. Скажите, а можно ли как то узнать наступивший конец файла. Например, если количество строк в файле неизвестно, а нужно организовать цикл по их считыванию и прервать его по окончанию файла. Елена, здравствуйте! Помогите, пожалуйста. Есть код, работающий, но вывод делает в консоль, а так как вывод очень большой, то все результаты там не помещаются, только малая последняя часть. Подскажите, пожалуйста, где и что изменить, чтоб вывод записывало в файл. Если можно очень подробно или прям конкретным примером, я со всем этим только только столкнулась, поэтому пока не особо соображаю(( Вот мой код 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 import static java.lang.System.out;
import java.util.Arrays;
class Combinations
private static final int M = 12;
private static final int N = 24;
private static int [] generateCombinations( int [] arr)
if (arr == null)
arr = new int [M];
for ( int i = 0; i < M; i++)
arr[i] = i + 1;
return arr;
>
for ( int i = M - 1; i >= 0; i--)
if (arr[i] < N - M + i + 1)
arr[i]++;
for ( int j = i; j < M - 1; j++)
arr[j + 1] = arr[j] + 1;
return arr;
>
return null;
>
public static void main(String args[])
int [] arr = null;
while ((arr = generateCombinations(arr)) != null)
out.println(Arrays.toString(arr));
>
>
В настройках консоли (меню в верхнем левом углу) изменить размер буфера Думаю, что "в правильную". Можно попробовать взять, например, среднее арифметическое для каждой точки из двух файлов. Но это нужно анализировать при отладке. Елена, здравствуйте, с вами можно как-то связаться, помимо того как здесь в комментариях? Можно через форму обратной связи на сайте или через ВК Елена, здравствуйте. Подскажите, пожалуйста, как можно сделать так, чтобы из первой строки файла считывался размер массива, а из второй - его элементы, количество которых равно значению из первой строки. Не нашла у вас на сайте ничего про построчный ввод из файла. Заранее спасибо. Ввод из файла осуществляется аналогично консольному вводу. После считывания порции данных указатель позиции файла автоматически перемещается на ее конец. Да, но у вас в статьях нет ничего про, к примеру, getline. По вашим статьям я изучаю практически все, очень понятно и доходчиво написано, но этот блок то ли я не могу найти, то ли его нет. Подскажите, у вас на сайте есть статья, где более подробно описывается файловый ввод и вывод? Здравствуйте, попыталась сделать вывод данных в файл, но почему то только создался документ, а данных там нет. Что не так?

ofstream fout( "file.txt" , ios::out);
fout.open( "file.txt" , ios::out);
for ( int i = 0; i < SIZE; i++)
for ( int j = 0; j < SIZE; j++)
printf( "%5d " , a[i][j]);
printf( "\n" );

Вы выводите в файл указатель на строку, а не элементы матрицы Не совсем понимаю цель этого действия. Почему нельзя создать пустую строку? А вообще sr[0]=0; И ещё один вопрос. Можно ли ввести несколько слов с консоли в одно значение char? Можно ли как-то скопировать половину строки ? Выше вы копировали от середины и до конца, но мне нужно наоборот- от начала до середины ( или 10-го символа) Вроде рассмотрены оба варианта: поиск позиции от начала строки и от конца Не совсем правильно сформулировала , от определённого индекса до определённого индекса. То есть, у нас есть строка(char sr[50]="blablablabla";) Я хочу скопировать с третього индекса по 10. Мы с файлом работе м или со строкой? Если со строкой, то функция strncpy(&sr[3], 7, dst); 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 надо сделать типа чтобы еще можно было добавить людей в список и выровнять это все Почему файл объявлен как поток вывода, а открывается для ввода? Чему равен count? Где тут люди? Почему при вводе нет цикла? 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

Работа файлового ввода/вывода в языке C++ почти аналогична работе обычных потоков ввода/вывода (но с небольшими нюансами).

Классы файлового ввода/вывода

Есть три основных класса файлового ввода/вывода в языке C++:

ofstream (является дочерним классу ostream);

fstream (является дочерним классу iostream ).

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

В отличие от потоков cout, cin, cerr и clog, которые сразу же можно использовать, файловые потоки должны быть явно установлены программистом. То есть, чтобы открыть файл для чтения и/или записи, нужно создать объект соответствующего класса файлового ввода/вывода, указав имя файла в качестве параметра. Затем, с помощью оператора вставки ( << ) или оператора извлечения ( >> ), можно записывать данные в файл или считывать содержимое файла. После проделывания данных действий нужно закрыть файл — явно вызвать метод close() или просто позволить файловой переменной ввода/вывода выйти из области видимости (деструктор файлового класса ввода/вывода закроет этот файл автоматически вместо нас).

Файловый вывод

Для записи в файл используется класс ofstream . Например:

// Класс ofstream используется для записи данных в файл. // Если мы не можем открыть этот файл для записи данных, cerr << "Uh oh, SomeText.txt could not be opened for writing!" << endl ; // Когда outf выйдет из области видимости, то деструктор класса ofstream автоматически закроет наш файл

Обратите внимание, мы также можем использовать метод put() для записи одного символа в файл.

Файловый ввод

Теперь мы попытаемся прочитать содержимое файла, который создали в предыдущем примере. Обратите внимание, ifstream возвратит 0 , если мы достигли конца файла (это удобно для определения «длины» содержимого файла). Например:

// ifstream используется для чтения содержимого файла. // Если мы не можем открыть этот файл для чтения его содержимого, cerr << "Uh oh, SomeText.txt could not be opened for reading!" << endl ; // то перемещаем эти данные в строку, которую затем выводим на экран // Когда inf выйдет из области видимости, то деструктор класса ifstream автоматически закроет наш файл

Результат выполнения программы:

Хм, это не совсем то, что мы хотели. Как мы уже узнали на предыдущих уроках, оператор извлечения работает с «отформатированными данными», т.е. он игнорирует все пробелы, символы табуляции и символ новой строки. Чтобы прочитать всё содержимое как есть, без его разбивки на части (как в примере, приведенном выше), нам нужно использовать метод getline():

// ifstream используется для чтения содержимого файлов. // Мы попытаемся прочитать содержимое файла SomeText.txt // Если мы не можем открыть файл для чтения его содержимого, cerr << "Uh oh, SomeText.txt could not be opened for reading!" << endl ; // то перемещаем то, что можем прочитать, в строку, а затем выводим эту строку на экран // Когда inf выйдет из области видимости, то деструктор класса ifstream автоматически закроет наш файл

Результат выполнения программы:

Буферизованный вывод

Вывод в языке C++ может быть буферизован. Это означает, что всё, что выводится в файловый поток, не может сразу же быть записанным на диск (в конкретный файл). Это сделано, в первую очередь, по соображениям производительности. Когда данные буфера записываются на диск, то это называется очисткой буфера. Одним из способов очистки буфера является закрытие файла. В таком случае всё содержимое буфера будет перемещено на диск, а затем файл будет закрыт.

Буферизация вывода обычно не является проблемой, но при определенных обстоятельствах она может вызвать проблемы у неосторожных новичков. Например, когда в буфере хранятся данные, а программа преждевременно завершает свое выполнение (либо в результате сбоя, либо путем вызова функции exit()). В таких случаях деструкторы классов файлового ввода/вывода не выполняются, файлы никогда не закрываются, буферы не очищаются и наши данные теряются навсегда. Вот почему хорошей идеей является явное закрытие всех открытых файлов перед вызовом функции exit().

Также буфер можно очистить вручную, используя метод ostream::flush() или отправив std::flush в выходной поток. Любой из этих способов может быть полезен для обеспечения немедленной записи содержимого буфера на диск в случае сбоя программы.

Интересный нюанс: Поскольку std::endl; также очищает выходной поток, то его чрезмерное использование (приводящее к ненужным очисткам буфера) может повлиять на производительность программы (так как очистка буфера в некоторых случаях может быть затратной операцией). По этой причине программисты, которые заботятся о производительности своего кода, часто используют \n вместо std::endl для вставки символа новой строки в выходной поток, дабы избежать ненужной очистки буфера.

Режимы открытия файлов

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

app — открывает файл в режиме добавления;

ate — переходит в конец файла перед чтением/записью;

binary — открывает файл в бинарном режиме (вместо текстового режима);

in — открывает файл в режиме чтения (по умолчанию для ifstream );

out — открывает файл в режиме записи (по умолчанию для ofstream );

trunc — удаляет файл, если он уже существует.

Можно указать сразу несколько флагов путем использования побитового ИЛИ (|).

ifstream по умолчанию работает в режиме ios::in;

ofstream по умолчанию работает в режиме ios::out;

fstream по умолчанию работает в режиме ios::in ИЛИ ios::out, что означает, что вы можете выполнять как чтение содержимого файла, так и запись данных в файл.

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

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


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

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

  • 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 - текущая позиция (любая)

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

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

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

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