2. Открытие и закрытие файлов.
В языке Си функции работы с фалом находятся в библиотеке stdio. В качестве файловой переменной там определена структура FILE, причём это не имя структуры, а тип данных. Так как функции, обрабатывающие файлы, могут изменять файловую переменную, они всегда используют указатель на неё, который так и называется – файловый указатель.
Открытие и закрытие файла
Для открытия файла служит функция fopen, продекларированная следующим образом:
FILE *fopen(char *name; char *mode);
Эта функция возвращает файловый указатель, либо NULL, если открыть файл не получилось, а принимает name – строку с именем файла или путём к нему и mode – строку с режимом открытия. Существуют следующие режимы открытия: Режим Назначение
"r" Только чтение, открытие несуществующего файла невозможно.
"r+" Чтение и запись, открытие несуществующего файла невозможно.
"w" Запись в пустой файл. Если файл не существует, то он создаётся, а если существует, то вся информация в нём стирается.
"w+" Чтение и запись со стиранием при открытии. Если файл не существует, то он создаётся.
"a" Запись в конец – запись всегда осуществляется только после последнего байта файла.
"a+" Запись в конец с возможностью чтения.
Закрытие файла выполняет функция fclose, принимающая в качестве единственного аргумента файловый указатель.
Побайтовый ввод
Несмотря на то, что каждый файл представляет собой массив байт, он не является массивом с точки зрения языка Си, а потому доступ к его элементам по индексу невозможен. Но существует аналог индекса – это указатель текущей позиции, хранящийся в файловой переменной. Считывание одного байта из текущей позиции выполняет функция getc, продекларированная следующим образом:
int getc(FILE* fp);
Считав значение, из файла fp, она увеличивает значение текущей позиции на 1. Это может привести к ситуации выхода за границу существующего файла, такую ситуацию надо корректно обрабатывать. Поэтому getc имеет тип int, и если файл кончился, то она ничего из него не считывает, а возвращает некоторое значение, которое не может быть значением одного байта. Это значение представляет собой константу EOF, продекларированную в stdio. Следует помнить, что EOF не является значением, находящимся в файле и считываемым из него, это только результат обработки ошибки.
Определение конца файла
Не всегда удобно считывать значения из файла и проверять, не равно ли значение EOF. Поэтому существует функция feof:
int feof(FILE* fp);
Если из фала можно считывать, то она возвращает значение 0, а если достигнут конец файла, то ненулевое значение.
Побайтовый вывод
Для записи одного символа в файл используется функция putc:
int putc(int value, FILE* fp);
Эта функция записывает value в текущую позицию, а затем увеличивает её значение на 1, причём запись будет осуществлена, даже если достигнут конец файла: его размер будет автоматически увеличен. Она возвращает записанное значение, либо EOF, если записать не удалось.
Изменение позиции в файле
Для принудительного изменения значения текущей позиции служит функция fseek:
int fseek(FILE* fp, long int offset, int origin);
Она увеличивает значение текущей позиции файлового указателя fp на величину offset (в том числе и отрицательную), а origin определяет, откуда ведётся отсчёт. Этим аргументом могут быть три константы, определённые в stdio:
SEEK_SET – отсчёт ведётся от начала файла.
SEEK_CUR – отсчёт ведётся от текущей позиции.
SEEK_END – отсчёт ведётся от конца файла, причём в сторону увеличения размера: если указано положительное значение offset, то файл расширяется до необходимого размера, а пустые поля заполняются нулями.
Режимы "a" и "a+" при открытии файла устанавливают текущую позицию на конец файла, туда же она устанавливается при каждом вызове функции записи, в независимости от того, где она была до вызова функции.
Получение позиции
Функция int ftell(FILE* fp); возвращает текущую позицию файлового указателя.
Сброс буфера
Буфер сбрасывается автоматически при закрытии файла и при необходимости обратиться к данным, лежащим вне его, но может возникнуть и необходимость сбросить его принудительно. Для этого служит функции fflush, единственным аргументом которой является файловый указатель, для которого осуществляется сброс.
Форматный ввод-вывод
Для работы с файлами существуют и функции форматного ввода-вывода – fprintf и fscanf. Они аналогичны printf и scanf, за тем исключением, что первым их аргументом является файловый указатель, а строка формата – вторым. Они перемещают текущую позицию на количество считанных или записанных символов.
Бинарные и текстовые файлы
Форматный ввод-вывод позволяет, в том числе, считывать из файла строки. Но это связано с определённым затруднением: в UNIX-подобных ОС переход на новую строку обозначается символом '\n', а в DOS и Windows – парой символов "\n\r". Функции форматного ввода-вывода по умолчанию меняют '\n' на "\n\r", если программа запускается в DOS, и наоборот – если в UNIX. Но в случае файла, не являющегося текстовым, это приведёт к потере данных. Поэтому в таком случае нужно к строке режима открытия добавить букву 'b' (от англ. binary – двоичный, в противоположность текстовому), которая отключит это преобразование.