Работа с файлами в C: мастерство ввода-вывода с fopen, fprintf, fread и fseek
Работа с файлами в C
Это руководство проведет вас через ввод-вывод в файлах на C, охватывая стандартные и бинарные операции с понятными практическими примерами.
Файл — это логический контейнер на носителе компьютера, хранящий данные для долгосрочного использования.
Зачем использовать файлы?
- Данные сохраняются после завершения программы, предотвращая потерю информации.
- Большие объемы данных можно сохранить один раз и быстро получать к ним доступ несколькими командами C.
- Файлы можно переносить между компьютерами без изменений.
Типы файлов
В C вы столкнетесь с двумя основными типами файлов:
- Текстовые файлы
- Бинарные файлы
Текстовые файлы
Обычные текстовые файлы (например, .txt) редактируются любым текстовым редактором. Их легко читать, поддерживать и передавать, но они занимают больше места и обеспечивают минимальную безопасность.
Бинарные файлы
Бинарные файлы (обычно .bin) хранят данные как необработанные байты (0 и 1). Они компактны, нечитаемы человеком и обеспечивают лучшую целостность и безопасность данных.
Основные файловые операции
Независимо от типа, работа с файлами в C вращается вокруг четырех операций:
- Создание нового файла
- Открытие существующего файла
- Закрытие файла
- Чтение из файла или запись в файл
Подготовка файлового указателя
Все файловые операции требуют указатель FILE * для ссылки на открытый файл:
FILE *fptr;
Открытие файлов: создание и редактирование
Функция fopen() (объявлена в stdio.h) открывает файл и возвращает указатель FILE *. Ее синтаксис:
fptr = fopen("filename", "mode");
Примеры использования:
fopen("E:\\cprogram\\newprogram.txt", "w");
fopen("E:\\cprogram\\oldprogram.bin", "rb");
Пояснение:
newprogram.txtсоздается (если отсутствует) и открывается для записи в режиме'w', который перезаписывает существующее содержимое.oldprogram.binоткрывается для бинарного чтения в режиме'rb'; попытка записи завершится неудачей.
| Режим | Значение | Поведение, если файл отсутствует |
|---|---|---|
r | Открыть для чтения | Возвращает NULL |
rb | Открыть для бинарного чтения | Возвращает NULL |
w | Открыть для записи (перезапись) | Создает файл, если отсутствует |
wb | Открыть для бинарной записи (перезапись) | Создает файл, если отсутствует |
a | Открыть для добавления | Создает файл, если отсутствует |
ab | Открыть для бинарного добавления | Создает файл, если отсутствует |
r+ | Чтение и запись | Возвращает NULL |
rb+ | Чтение и запись в бинарном режиме | Возвращает NULL |
w+ | Чтение и запись (перезапись) | Создает файл, если отсутствует |
wb+ | Чтение и запись в бинарном режиме (перезапись) | Создает файл, если отсутствует |
a+ | Чтение и добавление | Создает файл, если отсутствует |
ab+ | Чтение и бинарное добавление | Создает файл, если отсутствует |
Закрытие файла
После всех операций ввода-вывода всегда закрывайте файл с помощью fclose() для освобождения ресурсов и сброса буферов:
fclose(fptr);
Ввод-вывод текстовых файлов
Текстовые файлы обрабатываются с помощью fprintf() и fscanf() — файловых аналогов printf() и scanf(). Они требуют указатель FILE * в качестве первого аргумента.
Пример 1: Запись в текстовый файл
#include <stdio.h>
#include <stdlib.h>
int main() {
int num;
FILE *fptr;
// Настройте путь под вашу ОС
fptr = fopen("C:\\program.txt", "w");
if (fptr == NULL) {
printf("Error opening file\n");
exit(EXIT_FAILURE);
}
printf("Enter a number: ");
scanf("%d", &num);
fprintf(fptr, "%d", num);
fclose(fptr);
return 0;
}
Эта программа считывает целое число от пользователя и записывает его в program.txt.
Пример 2: Чтение из текстового файла
#include <stdio.h>
#include <stdlib.h>
int main() {
int num;
FILE *fptr;
fptr = fopen("C:\\program.txt", "r");
if (fptr == NULL) {
printf("Error opening file\n");
exit(EXIT_FAILURE);
}
fscanf(fptr, "%d", &num);
printf("Value read: %d\n", num);
fclose(fptr);
return 0;
}
Запуск после первого примера покажет сохраненное целое число.
Дополнительные утилиты вроде fgetc() и fputc() следуют той же схеме.
Ввод-вывод бинарных файлов
Бинарные файлы манипулируются с помощью fwrite() для записи и fread() для чтения. Обе функции принимают четыре аргумента: указатель на данные, размер каждого элемента, количество элементов и указатель FILE *.
Запись в бинарный файл
fwrite(addressData, sizeData, numberData, filePointer);
Пример 3: Запись в бинарный файл с fwrite()
#include <stdio.h>
#include <stdlib.h>
struct threeNum {
int n1, n2, n3;
};
int main() {
int i;
struct threeNum num;
FILE *fptr;
fptr = fopen("C:\\program.bin", "wb");
if (fptr == NULL) {
printf("Error opening file\n");
exit(EXIT_FAILURE);
}
for (i = 1; i < 5; ++i) {
num.n1 = i;
num.n2 = 5 * i;
num.n3 = 5 * i + 1;
fwrite(&num, sizeof(struct threeNum), 1, fptr);
}
fclose(fptr);
return 0;
}
Чтение из бинарного файла
Соответствующая сигнатура fread() зеркалит fwrite():
fread(addressData, sizeData, numberData, filePointer);
Пример 4: Чтение из бинарного файла с fread()
#include <stdio.h>
#include <stdlib.h>
struct threeNum {
int n1, n2, n3;
};
int main() {
int i;
struct threeNum num;
FILE *fptr;
fptr = fopen("C:\\program.bin", "rb");
if (fptr == NULL) {
printf("Error opening file\n");
exit(EXIT_FAILURE);
}
for (i = 1; i < 5; ++i) {
fread(&num, sizeof(struct threeNum), 1, fptr);
printf("n1: %d\tn2: %d\tn3: %d\n", num.n1, num.n2, num.n3);
}
fclose(fptr);
return 0;
}
Эта программа воспроизводит данные, записанные в примере 3.
Случайный доступ с fseek()
Когда файл содержит много записей, последовательный проход к конкретной записи может быть неэффективным. fseek() перемещает файловый указатель в произвольную позицию, обеспечивая прямой доступ.
Синтаксис
fseek(FILE *stream, long int offset, int whence);
stream: указатель, возвращенныйfopen().offset: количество байт для перемещения.whence: начальная точка —SEEK_SET,SEEK_CURилиSEEK_END.
| Константа | Значение |
|---|---|
SEEK_SET | Смещение от начала файла. |
SEEK_CUR | Смещение от текущей позиции курсора. |
SEEK_END | Смещение от конца файла. |
Пример 5: Чтение в обратном порядке с fseek()
#include <stdio.h>
#include <stdlib.h>
struct threeNum {
int n1, n2, n3;
};
int main() {
int i;
struct threeNum num;
FILE *fptr;
fptr = fopen("C:\\program.bin", "rb");
if (fptr == NULL) {
printf("Error opening file\n");
exit(EXIT_FAILURE);
}
// Переход к последней записи
fseek(fptr, -sizeof(struct threeNum), SEEK_END);
for (i = 1; i < 5; ++i) {
fread(&num, sizeof(struct threeNum), 1, fptr);
printf("n1: %d\tn2: %d\tn3: %d\n", num.n1, num.n2, num.n3);
// Шаг назад на две записи (текущая + еще одна) для чтения предыдущей
fseek(fptr, -2 * sizeof(struct threeNum), SEEK_CUR);
}
fclose(fptr);
return 0;
}
Этот фрагмент демонстрирует, как обходить бинарный файл в обратном направлении, начиная с последней записи.
Язык C
- Мастерство файловых операций в Java с java.io: создание, чтение, запись и удаление
- Понимание STL-файлов: основа 3D-печати
- Работа с файлами в Verilog: открытие, чтение, запись и закрытие
- Освоение ввода-вывода файлов в C: создание, открытие и управление файлами
- Заголовочные файлы в C: типы, подключение и лучшие практики
- Обработка ошибок в C: лучшие практики и техники
- Ввод-вывод в файлы в C++: чтение и запись с fstream
- Освоение обработки сигналов в C++: безопасное управление прерываниями и корректное завершение программы
- Обработка исключений в C#: try, catch, finally, throw и лучшие практики
- Работа с файлами в C#: FileStream, StreamReader, StreamWriter и File API