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

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

Режимы открытия те же, что и у текстовых, но с буквой b справа

rb - чтение, файл не создается

wb - пустой для записи, если есть - всё стирается

ab - дописать в файл, создается

<img src="https://3074527236-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOlTieA4l7aQXw27w94AS%2Fuploads%2F2BjpxIny0DbJD7qhniys%2Fimage.png?alt=media&#x26;token=866aa43f-10d2-44b6-9057-7b5a3ac063c0" alt="" width="100%">

<figure><img src="/files/uSdGnXp8HYYIE6pczrN8" alt=""><figcaption></figcaption></figure>

### Алгоритм работы <a href="#algoritm-raboty" id="algoritm-raboty"></a>

В отличие от текстовых файлов, в бинарных можно удалять, добавлять, сортировать элементы не выгружая их в массив.

```c
// 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); // Закрываем файл
}

```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://op-al.gitbook.io/s-30-voprosy-i-dop.-voprosy/17.-binarnye-faily.-funkcii-dlya-raboty-s-binarnymi-failami.-algoritmy-raboty-s-binarnymi-failami..md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
