Освоение ввода-вывода файлов в C: создание, открытие и управление файлами
Предыдущая глава объясняла стандартные устройства ввода и вывода, обрабатываемые языком программирования C. Эта глава охватывает, как программисты на C могут создавать, открывать, закрывать текстовые или бинарные файлы для своего хранилища данных.
Файл представляет собой последовательность байтов, независимо от того, является ли это текстовым файлом или бинарным файлом. Язык программирования C предоставляет доступ к высокоуровневым функциям, а также к низкоуровневым (уровню ОС) вызовам для обработки файлов на ваших устройствах хранения. Эта глава проведет вас через важные вызовы для управления файлами.
Открытие файлов
Вы можете использовать функцию fopen() для создания нового файла или открытия существующего файла. Этот вызов инициализирует объект типа FILE, содержащий всю информацию, необходимую для управления потоком. Прототип этого вызова функции:
FILE *fopen( const char * filename, const char * mode );
Здесь filename — строковый литерал, который вы используете для именования вашего файла, и режим доступа mode может иметь одно из следующих значений:
| № | Режим и описание |
|---|---|
| 1 | r Открывает существующий текстовый файл для чтения. |
| 2 | w Открывает текстовый файл для записи. Если он не существует, создается новый файл. Программа начнет записывать содержимое с начала файла. |
| 3 | a Открывает текстовый файл для записи в режиме добавления. Если не существует, создается новый файл. Программа начнет добавлять содержимое в существующее содержимое файла. |
| 4 | r+ Открывает текстовый файл для чтения и записи. |
| 5 | w+ Открывает текстовый файл для чтения и записи. Сначала усекает файл до нулевой длины, если он существует, иначе создает файл, если он не существует. |
| 6 | a+ Открывает текстовый файл для чтения и записи. Создает файл, если он не существует. Чтение начнется с начала, но запись может быть только добавлена. |
Если вы собираетесь обрабатывать бинарные файлы, то вы будете использовать следующие режимы доступа вместо вышеупомянутых:
"rb", "wb", "ab", "rb+", "r+b", "wb+", "w+b", "ab+", "a+b"
Закрытие файла
Для закрытия файла используйте функцию fclose(). Прототип этой функции:
int fclose( FILE *fp );
Функция fclose() возвращает ноль при успехе, или EOF, если есть ошибка при закрытии файла. Эта функция фактически сбрасывает любые данные, все еще ожидающие в буфере, в файл, закрывает файл и освобождает любую память, использованную для файла. EOF — константа, определенная в заголовочном файле stdio.h.
Существует множество функций, предоставляемых стандартной библиотекой C для чтения и записи файла, символ за символом или в виде строки фиксированной длины.
Запись в файл
Ниже приведена самая простая функция для записи отдельных символов в поток:
int fputc( int c, FILE *fp );
Функция fputc() записывает символьное значение аргумента c в выходной поток, на который ссылается fp. Она возвращает записанный символ при успехе, иначе EOF в случае ошибки. Вы можете использовать следующие функции для записи нуль-терминированной строки в поток:
int fputs( const char *s, FILE *fp );
Функция fputs() записывает строку s в выходной поток, на который ссылается fp. Она возвращает неотрицательное значение при успехе, иначе EOF возвращается в случае любой ошибки. Вы также можете использовать функцию int fprintf(FILE *fp, const char *format, ...) для записи строки в файл. Попробуйте следующий пример.
Убедитесь, что у вас есть каталог /tmp. Если его нет, то перед продолжением вы должны создать этот каталог на вашей машине.
#includemain() { FILE *fp; fp = fopen("/tmp/test.txt", "w+"); fprintf(fp, "This is testing for fprintf...\n"); fputs("This is testing for fputs...\n", fp); fclose(fp); }
Когда приведенный выше код компилируется и выполняется, он создает новый файл test.txt в каталоге /tmp и записывает две строки, используя две разные функции. Давайте прочитаем этот файл в следующем разделе.
Чтение файла
Ниже приведена самая простая функция для чтения одного символа из файла:
int fgetc( FILE *fp );
Функция fgetc() читает символ из входного файла, на который ссылается fp. Возвращаемое значение — прочитанный символ, или в случае любой ошибки возвращает EOF. Следующая функция позволяет читать строку из потока:
char *fgets( char *buf, int n, FILE *fp );
Функция fgets() читает до n-1 символов из входного потока, на который ссылается fp. Она копирует прочитанную строку в буфер buf, добавляя символ null для завершения строки.
Если эта функция встречает символ новой строки '\n' или конец файла EOF до того, как они прочитали максимальное количество символов, то она возвращает только прочитанные символы до этой точки, включая символ новой строки. Вы также можете использовать функцию int fscanf(FILE *fp, const char *format, ...) для чтения строк из файла, но она останавливает чтение после встречи первого пробела.
#includemain() { FILE *fp; char buff[255]; fp = fopen("/tmp/test.txt", "r"); fscanf(fp, "%s", buff); printf("1 : %s\n", buff); fgets(buff, 255, (FILE*)fp); printf("2: %s\n", buff); fgets(buff, 255, (FILE*)fp); printf("3: %s\n", buff); fclose(fp); }
Когда приведенный выше код компилируется и выполняется, он читает файл, созданный в предыдущем разделе, и производит следующий результат:
1 : This 2: is testing for fprintf... 3: This is testing for fputs...
Давайте посмотрим немного подробнее, что здесь произошло. Сначала fscanf() прочитал только This, потому что после этого он встретил пробел, второй вызов для fgets() читает оставшуюся строку до встречи конца строки. Наконец, последний вызов fgets() читает вторую строку полностью.
Функции двоичного ввода-вывода
Существует две функции, которые могут использоваться для двоичного ввода и вывода:
size_t fread(void *ptr, size_t size_of_elements, size_t number_of_elements, FILE *a_file); size_t fwrite(const void *ptr, size_t size_of_elements, size_t number_of_elements, FILE *a_file);
Обе эти функции должны использоваться для чтения или записи блоков памяти — обычно массивов или структур.
Язык C
- Ввод-вывод в C: scanf() и printf() — подробное руководство
- Работа с файлами в C: мастерство ввода-вывода с fopen, fprintf, fread и fseek
- Работа с файлами в Python: открытие, чтение, запись и управление
- Axiomtek IPS960-511-PoE: All-in-One rugged визионный контроллер для промышленного контроля
- acceed EDAM-4200: Интегрированные I/O-модули для масштабируемой надежной передачи данных
- Функции в C: объявление, определение, вызов, аргументы (по значению и по ссылке), рекурсия
- Заголовочные файлы в C: типы, подключение и лучшие практики
- I/O карты объяснены: как они работают и почему важны
- Экспорт данных из MATLAB: форматы файлов и методы
- Работа с файлами в C#: FileStream, StreamReader, StreamWriter и File API