Урок №212. Базовый файловый ввод/вывод

  Юрий  | 

    | 

  Обновл. 8 Фев 2019  | 

 1179

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

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

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

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

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

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

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

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

Если вы загляните в каталог вашего проекта (ПКМ по вкладке с названием вашего .cpp файла в Visual Studio > «Открыть содержащую папку»), то увидите файл с именем SomeText.txt, в котором находятся следующие строчки:

See line #1!
See line #2!

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

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


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

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

See
line
#1!
See
line
#2!

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

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

See line #1!
See line #2!

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

Вывод в 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, что означает, что вы можете выполнять как чтение содержимого файла, так и запись данных в файл.

Теперь давайте напишем программу, которая добавит две строки в ранее созданный файл SomeText.txt:

Теперь, если мы посмотрим на SomeText.txt (запустим одну из программ выше с чтением файла или откроем этот файл в каталоге проекта), то увидим следующее:

See line #1!
See line #2!
See line #3!
See line #4!

Явное открытие файлов с помощью метода open()

Точно так же, как мы явно закрываем файл с помощью метода close(), точно так же мы можем и явно открывать файл с помощью метода open(). open() работает аналогично конструкторам класса файлового ввода/вывода: принимает имя файла и режим (необязательно), в котором нужно открыть файл, в качестве параметров. Например:

Результат:

See line #1!
See line #2!
See line #3!

На этом всё. В следующем уроке мы рассмотрим рандомный файловый ввод/вывод.


Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (12 оценок, среднее: 4,92 из 5)
Загрузка...

Добавить комментарий

Ваш E-mail не будет опубликован. Обязательные поля помечены *