2️⃣17. Бинарные файлы. Функции для работы с бинарными файлами. Алгоритмы работы с бинарными файлами.

Бинарные файлы - файлы, данные в котором записаны как последовательность произвольных байтов.

Режимы открытия те же, что и у текстовых, но с буквой 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, &current_record); // Смещаем запись влево
    }
    int new_file_size = (records_count - 1) * sizeof(student); // Считаем новый размер файла
    setFileSize(new_file_size); // Устанавливаем новый размер файла
    fclose(pfile); // Закрываем файл
}

Last updated