Бинарные файлы - файлы, данные в котором записаны как последовательность произвольных байтов.
Режимы открытия те же, что и у текстовых, но с буквой b справа
rb - чтение, файл не создается
wb - пустой для записи, если есть - всё стирается
ab - дописать в файл, создается
Алгоритм работы
В отличие от текстовых файлов, в бинарных можно удалять, добавлять, сортировать элементы не выгружая их в массив.
// Binary template
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <io.h>
#define FILE_EXIST 1
#define FILE_NOT_EXIST 0
typedef struct student_t {
char surname[20];
int group;
int grades[3];
} student;
// Base check
int fileExist();
// I/O Binary data
void inputBinaryData();
void outputFile();
// quantity of records
int sizeFile();
int quantityStruct();
// Read and write
student readRecordFromFile(int index);
void writeRecord(int index, const student *recordToWrite);
// Specialize func
void swapRecordsInFile(int indexR1, int indexR2);
void setFileSize(int new_size);
void removeRecordFromFile(int record_index);
int main () {
if(!fileExist()){
inputBinaryData();
}
// workWithBinary (Здесь основная логика работы с бинаркой)
outputFile();
return 0;
}
int fileExist(){
int status = FILE_EXIST; // Status = файл существует
FILE *file = fopen("aaa.dat", "rb"); // Открываем на чтение
if (file == NULL) { // Если файл не существует
status = FILE_NOT_EXIST; // Присваиваем статус = файл не существует
}
fclose(file); // Закрываем файл
return status; // Возвращаем статус
}
void inputBinaryData() {
int n; // Кол-во студентов
printf("Input quantity of students: ");
scanf("%d", &n); // Считываем кол-во студентов
student *arrStudents = (student *)malloc(sizeof(student) * n); // Выделяем память под студентов
if(arrStudents != NULL) { // Проверяем на выделение памяти
FILE *file = fopen("aaa.dat", "wb"); // Открываем на запись файл
for (int i = 0; i < n; i++) { // Проходимся до N кол-во студентов
student tmp; // Временная структура
printf("Input surname: ");
scanf("%20s", tmp.surname);
printf("Input group: ");
scanf("%d", &tmp.group);
for (int k = 0; k < 3; k++) { // Проходимся по каждой оценке, каждого студента
printf("Input grades [%d]: ", k);
scanf("%d", &tmp.grades[k]);
}
// Копируем данные в массив структур
strcpy((*(arrStudents+i)).surname, tmp.surname);
(*(arrStudents+i)).group = tmp.group;
(*(arrStudents+i)).grades[0] = tmp.grades[0];
(*(arrStudents+i)).grades[1] = tmp.grades[1];
(*(arrStudents+i)).grades[2] = tmp.grades[2];
}
// Записываем массив структур студентов в файл
fwrite(arrStudents, sizeof(student), n, file);
fclose(file); // Закрываем файл
free(arrStudents); // Очищаем массив структур
}
}
void outputFile () {
int sizeStruct = quantityStruct(); // Получаем количество записей
for(int i = 0; i < sizeStruct; i++){ // Идем по каждой записи
student data = readRecordFromFile(i); // Считываем по одной записи
printf("Surname: %s\nGroup: %d\nGrades[1]: %d\nGrades[2]: %d\nGrades[3]: %d\n", data.surname, data.group, data.grades[0], data.grades[1], data.grades[2]);
// Выводим структуру записи
}
}
int sizeFile() {
FILE *file = fopen("aaa.dat", "rb"); // Открываем на чтение файл
fseek(file, 0, SEEK_END); // Переходим в самый конец файл
int size = ftell(file); // Возвращаем размер файла на котором находится указатель
fclose(file); // Закрываем файл
return size; // Возвращаем размер
}
int quantityStruct() {
return sizeFile()/sizeof(student); // Делим размер файла на размер одной структуры, чтобы узнать кол-во записей
}
student readRecordFromFile(int index) {
FILE *file = fopen("aaa.dat", "rb"); // Открыаем на чтение
int size = index * sizeof(student); // Считаем нужное смещение чтобы взять нужную нам запись
fseek(file, size, SEEK_SET); // перемещаем указатель на нужное смещение
student data; // временная структура, куда сохраняем запись
fread(&data, sizeof(student), 1, file); // считываем запись во временную структуру
fclose(file); // закрываем файл
return data; // возвращаем запись
}
void writeRecord(int index, const student *recordToWrite) {
FILE *file = fopen("aaa.dat", "rb+"); // Открываем файл, нужно чтобы писать в уже существующие записи
int offset = sizeof(student) * index; // определяем смещение, чтобы записать в нужную часть
fseek(file, offset, SEEK_SET); // перемещаем указатель
fwrite(recordToWrite, sizeof(student), 1, file); // пишем структуру
fflush(file); // Принудительно проталкиваем данные в файл из буфера
rewind(file); // Перемещаем указатель в начало
fclose(file); // Закрываем файл
}
void swapRecordsInFile(int indexR1, int indexR2){
student r1 = readRecordFromFile(indexR1); // Запоминаем обе структуры
student r2 = readRecordFromFile(indexR2);
writeRecord(indexR2, &r1); // Перезаписываем их на места друг друга
writeRecord(indexR1, &r2);
}
void setFileSize(int new_size){
FILE *pfile = fopen("aaa.dat","rb+"); // Открываем на чтение и запись
int file_descriptor = fileno(pfile); // Создаем файловый дескриптор
chsize(file_descriptor, new_size); // Меняем размер файла на новый
fclose(pfile); // Закрываем файл
}
void removeRecordFromFile(int record_index){
FILE *pfile = fopen("aaa.dat","rb+"); // Открываем на чтение и запись
int records_count = quantityStruct(); // Получаем количество записей
for (int i = record_index + 1; i < records_count; i++) // Делаем смещение всех записей, чтобы удаляемая запись оказалась в конце
{
student current_record = readRecordFromFile(i); // Читаем запись
writeRecord(i-1, ¤t_record); // Смещаем запись влево
}
int new_file_size = (records_count - 1) * sizeof(student); // Считаем новый размер файла
setFileSize(new_file_size); // Устанавливаем новый размер файла
fclose(pfile); // Закрываем файл
}