Стандартные файлы и функции по работе с ними
Цель лекции: изучить понятия, характеристику и классификацию файлов и стандартных функций по работе с файлами, научиться решать задачи с использованием стандартных функций по работе с файлами на языке C++.
Файл – это именованная область внешней памяти, в которой хранится логически завершенный объем данных. Файл имеет следующие характерные особенности:
- имеет имя на диске, что дает возможность программам идентифицировать и работать с несколькими файлами;
- длина файла ограничивается только емкостью диска.
Часто бывает необходимо ввести некоторые данные из файла или вывести результаты в файл. Например, бывает необходимо обрабатывать массивы, которые слишком велики, чтобы полностью разместиться в памяти.
Файлы делятся на текстовые и двоичные.
Текстовый файл – это файл, в котором каждый символ из используемого набора символов хранится в виде одного байта (кода, соответствующего символу). Текстовые файлы разбиваются на несколько строк с помощью специального символа "конец строки". Текстовый файл заканчивается специальным символом "конец файла".
Двоичный файл – файл, данные которого представлены в бинарном виде. При записи в двоичный файл символы и числа записываются в виде последовательности байт (в своем внутреннем двоичном представлении в памяти компьютера).
Особенностью языка С++ является отсутствие в нем структурированных файлов. Все файлы рассматриваются как неструктурированная последовательность байтов. При таком подходе понятие файла распространяется и на различные устройства.
В С++ существуют специальные средства ввода-вывода данных. Все операции ввода-вывода реализуются с помощью функций, которые находятся в библиотеке С++. Библиотека С++ поддерживает три уровня ввода-вывода:
- потоковый ввод-вывод;
- ввод-вывод нижнего уровня;
- ввод-вывод для консоли и портов (зависит от ОС).
Поток – это абстрактное понятие, относящееся к любому переносу данных от источника к приемнику.
Функции библиотеки ввода-вывода языка С++, поддерживающие обмен данными с файлами на уровне потока, позволяют обрабатывать данные различных размеров и форматов, обеспечивая при этом буферизованный ввод и вывод. Таким образом, поток представляет собой этот файл вместе с предоставленными средствами буферизации.
Чтение данных из потока называется извлечением, вывод в поток – помещением (включением).
Поток определяется как последовательность байтов и не зависит от конкретного устройства, с которым производится обмен (оперативная память, файл на диске, клавиатура или принтер). Обмен с потоком для увеличения скорости передачи данных производится, как правило, через специальную область оперативной памяти – буфер. Буфер накапливает байты, и фактическая передача данных выполняется после заполнения буфера ( рис. 19.1). При вводе это дает возможность исправить ошибки, если данные из буфера еще не отправлены в программу.
При работе с потоком можно:
- открывать и закрывать потоки (связывать указатели на поток с конкретными файлами);
- вводить и выводить строку, символ, форматированные данные, порцию данных произвольной длины;
- анализировать ошибки ввода-вывода и достижения конца файла;
- управлять буферизацией потока и размером буфера;
- получать и устанавливать указатель текущей позиции в файле.
Когда программа начинает выполняться, автоматически открываются пять потоков, из которых основными являются:
- стандартный поток ввода (на него ссылаются, используя предопределенный указатель на поток stdin );
- стандартный поток вывода ( stdout );
- стандартный поток вывода сообщений об ошибках ( stderr ).
По умолчанию стандартному потоку ввода stdin ставится в соответствие клавиатура, а потокам stdout и stderr соответствует экран монитора.
В С++ операции с файлами можно осуществлять в двух режимах: форматированном и потоковом.
Рассмотрим основные функции для работы с файлами в форматированном режиме.
Функция открытия файла
Для работы с файлом в языке C++ необходима ссылка на файл. Для определения такой ссылки существует структура FILE, описанная в файле stdio.h. Данная структура содержит все необходимые поля для управления файлами, например: текущий указатель буфера, текущий счетчик байтов, базовый адрес буфера ввода-вывода, номер файла.
При открытии файла (потока) в программу возвращается указатель на поток (файловый указатель), являющийся указателем на объект структурного типа FILE. Этот указатель идентифицирует поток во всех последующих операциях.
Например:
#include<stdio.h> .............. FILE *fp;
Для открытия файла существует функция fopen, которая инициализирует файл.
fp=fopen(ИмяФайла, РежимОткрытия);
где fp – указатель на поток (файловый указатель);
ИмяФайла – указатель на строку символов, представляющую собой допустимое имя файла, в которое может входить спецификация файла (включает обозначение логического устройства, путь к файлу и собственно имя файла);
РежимОткрытия – указатель на строку режима открытия файла.
Например:
fp=fopen("t.txt","r");
Существуют несколько режимов открытия файлов.
Режим | Описание | Начинается с... |
---|---|---|
r | Открывает текстовый файл для чтения. Если файл не существует, то выдается ошибка при исполнении программы. | начала |
w | Открывает текстовый файл для записи. Если файл не существует, то он создается. Если файл уже существует, то удаляется его содержимое, файл перезаписывается | начала |
a | Открывает текстовый файл для добавления. Если файл не существует, то он создается. Если существует, то содержимое из него не удаляется. | конца |
r+ | Открывает текстовый файл для чтения и записи. Изменить размер файла нельзя. Если файл не существует, то выдается ошибка при исполнении программы. | начала |
w+ | Открывает текстовый файл для чтения и записи. Если файл не существует, то он создается. Если файл уже существует, то удаляется его содержимое, файл перезаписывается. | начала |
a+ | Открывает текстовый файл для чтения и записи. Если файл не существует, то он создается. Если существует, то содержимое из него не удаляется. | конца |
rb | Открывает двоичный файл для чтения. Если файл не существует, то выдается ошибка при исполнении программы. | начала |
wb | Открывает двоичный файл для записи. Если файл не существует, то он создается. Если файл уже существует, то удаляется его содержимое, файл перезаписывается. | начала |
ab | Открывает двоичный файл для добавления. Если файл не существует, то он создается. Если существует, то содержимое из него не удаляется. | конца |
r+b | Открывает двоичный файл для чтения и записи. Изменить размер файла нельзя. Если файл не существует, то выдается ошибка при исполнении программы. | начала |
rb+ | ||
w+b | Открывает двоичный файл для чтения и записи. Если файл не существует, то он создается. Если файл уже существует, то удаляется его содержимое, файл перезаписывается. | начала |
wb+ | ||
a+b | Открывает двоичный файл для чтения и записи. Если файл не существует, то он создается. Если существует, то содержимое из него не удаляется. | конца |
ab+ |
Поток можно открыть в текстовом ( t ) или двоичном ( b ) режиме. По умолчанию используется текстовый режим. В явном виде режим указывается следующим образом:
"r+b" или "rb" – двоичный (бинарный) режим;
"r+t" или "rt" – текстовый режим.
В файле stdio.h определена константа EOF, которая сообщает об окончании файла (отрицательное целое число).
При открытии файла могут возникать следующие ошибки:
- файл, связанный с потоком не найден (при чтении из файла);
- диск заполнен (при записи);
- диск защищен от записи (при записи) и т. п.
В этих случаях указатель на поток приобретет значение NULL (0). Указатель на поток, отличный от аварийного, не бывает равен NULL.
Для вывода сообщения об ошибке при открытии файла используется стандартная библиотечная функция из файла <stdio.h>:
void perror (const char*s);
Функция perror() выводит строку символов, адресуемую указателем s, за которой размещаются: двоеточие, пробел и сообщение об ошибке. Содержимое и формат сообщения определяются реализацией системы программирования.
Пример 1. Обнаружение и вывод ошибки при открытии файла.
#include "stdafx.h" #include <iostream> using namespace std; int _tmain(int argc, _TCHAR* argv[]){ FILE *fp; if ((fp=fopen("t.txt", "r"))==NULL) // выводит строку символов с сообщением об ошибке perror("ошибка при открытии файла"); system("pause"); return 0; }
Перед началом выполнения операций с файлами целесообразно получить подтверждение, что функция fopen() выполнилась успешно.