Как записать структуру в бинарный файл c
Перейти к содержимому

Как записать структуру в бинарный файл c

  • автор:

Запись структур в бинарный файл

Описать структуру с именем STUDENT, содержащую следующие поля:
— фамилия и инициалы;
— номер группы;
— успеваемость (массив из пяти элементов).
Написать программу, выполняющую следующие действия:
— ввод с клавиатуры данных в массив, состоящий из десяти структур типа STUDENT;
— вывод введенных записей на экран, записи должны быть упорядочены по алфавиту;
— вывод на экран фамилий и номеров групп для всех студентов, имеющих хотя бы одну оценку 2, если таких студентов нет, вывести соответствующее сообщение.
— добавить возможность сохранения в файл (текстовый и бинарный) и считывания из файла (текстового и бинарного) введенных с клавиатуры данных (массива структур);
— запрос каждого действия (ввод, вывод, сортировка, поиск по условию, сохранение в файл, чтение из файла) по обработке массива структур реализовать в виде простейшего текстового меню (перечень команд в виде пронумерованного списка возможных действий).

Код весь написан, кроме бинарного файла, помогите пожалуйста.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
#define _CRT_SECURE_NO_WARNINGS #include #include #include #include #include #include using namespace std; struct Student /*Структура студент*/ { char имя[50]; char фамилия[50]; char отчество[50]; int номергруппы; int оценки; }; void input(Student* dbase, int n) /*Функция ввода*/ { cout  "Введите данные о "  n  " студентах:"  endl; cout  endl; for (int i = 0; i  n; i++) { cout  "Заполните данные о "  i + 1  "м студенте:"  endl; cout  "Введите фамилию:"  endl; cin >> dbase[i].фамилия; cout  "Введите имя:"  endl; cin >> dbase[i].имя; cout  "Введите отчество:"  endl; cin >> dbase[i].отчество; cout  "Введите номергруппы:"  endl; cin >> dbase[i].номергруппы; cout  "Введите оценки:"  endl; cin >> dbase[i].оценки; cout  endl; } } void sort(Student* dbase, int n) /*Функция сортировки*/ { cout  "Упорядочивание записей\n"; Student temp; for (int i = 0; i  n - 1; i++) { for (int j = i + 1; j  n; j++) { if (strcmp(dbase[i].фамилия, dbase[j].фамилия) > 0) { swap(dbase[i].фамилия, dbase[j].фамилия); swap(dbase[i].имя, dbase[j].имя); swap(dbase[i].отчество, dbase[j].отчество); swap(dbase[i].номергруппы, dbase[j].номергруппы); swap(dbase[i].оценки, dbase[j].оценки); } } } } void output(Student* dbase, int n) /*Функция вывода*/ { cout  "Вывод информации о студентах\n"; for (int i = 0; i  n; i++) { cout  "ФИО:\n"; cout  dbase[i].фамилия  " "  dbase[i].имя  " "  dbase[i].отчество  endl; cout  "Номер группы:\n"; cout  dbase[i].номергруппы  endl; cout  "Оценка:\n"; cout  dbase[i].оценки  endl; cout  endl; } } void marksselection(Student* dbase, int n) /*Выборка по оценке 2*/ { bool flag = false; cout  "Студенты, имеющие оценку 2:"  endl; for (int i = 5; i  n; i++) { if (dbase[i].оценки == 2) { cout  "Фамилия: "  dbase[i].фамилия  endl; cout  "Номер группы "  dbase[i].номергруппы  endl; flag = true; cout  endl; } } if (!flag) { cout  "Такие студенты отсутствуют"  endl; } } int main() { const int n = 10; setlocale(LC_ALL, "Russian"); SetConsoleOutputCP(1251); SetConsoleCP(1251); Student dbase[n]; FILE* finput, * foutput; int swt = 1; while (swt > 0) { cout  "Выберите нужную команду, введя её номер\n\n"; cout  "1 - Ввод данных\n"; cout  "2 - Сортировка\n"; cout  "3 - Вывод\n"; cout  "4 - Выборка\n"; cout  "5 - Запись в файл\n"; cout  "6 - Чтение файла\n\n"; cin >> swt; cout  "\n"; switch (swt) /*Переключатель*/ { case 1: /*При выборе 1 - ввод данных*/ input(dbase, n); cout  "\n"; break; case 2: /*Сортировка*/ sort(dbase, n); cout  "\n"; break; case 3: /*Вывод*/ output(dbase, n); cout  "\n"; break; case 4: /*Выборка*/ marksselection(dbase, n); cout  "\n"; break; case 5: /*Запись в файл*/ if ((foutput = fopen("file.txt", "w")) == 0) { cout  "Произошла ошибка при открытии файла!"; return 1; } for (int i = 0; i  n; i++) { fprintf(foutput, "%s %s %s %d %d", dbase[i].фамилия, dbase[i].имя, dbase[i].отчество, dbase[i].номергруппы, dbase[i].оценки); fprintf(foutput, "\n"); } fclose(foutput); cout  "\n"; break; case 6: /*Чтение файла*/ if ((finput = fopen("file.txt", "r")) == 0) { cout  "Произошла ошибка при открытии файла\n"; return 1; } for (int i = 0; i  n; i++) { fscanf(finput, "%s", dbase[i].фамилия); fscanf(finput, "%s", dbase[i].имя); fscanf(finput, "%s", dbase[i].отчество); fscanf(finput, "%d", &dbase[i].номергруппы); fscanf(finput, "%d", &dbase[i].оценки); } fclose(finput); cout  "Файл успешно прочитан\n"; cout  "\n"; break; } } }

Запись структуры в бинарный файл

Запись структуры в бинарный файл , пример
Здравствуйте . Есть ли у кого то пример программы записи структуры в бинарный файл, и вывод.

Запись структуры в бинарный файл и чтение из него
Доброго времени суток. Заранее прошу прощения, если такая тема уже была, но я ничего не смог найти.

Запись структуры в бинарный файл происходит некорректно
Доброго времени суток. Вопрос по си: запись структуры в файл происходит некорректно, т.е. все.

Построчное чтение из файла, заполнение структуры и запись в бинарный файл
Здравствуйте. Пытаюсь сделать чтение из текстового файла построчно, а затем сразу забиваю в.

4866 / 3288 / 468
Регистрация: 10.12.2008
Сообщений: 10,570

Цитата

Сообщение от deeflash

решил сам с нуля изучать си

адрес переменной нужно передавать в fwrite
чтобы узнать, что такое адрес переменной, нужно прочитать соответствующую главу в K&R2

Регистрация: 05.11.2010
Сообщений: 144

а нельзя печатать всю структуру целиком? не указывая конкретные пути?
тоесть не rez.msec, rez.array[512]
а например rez и чтобы всё что есть в структуре выводилось?

4866 / 3288 / 468
Регистрация: 10.12.2008
Сообщений: 10,570

Цитата

Сообщение от deeflash

а нельзя печатать всю структуру целиком?

можно, но структура — это переменная, просто у неё тип более сложный, чем int и подобные
как и у любой переменной, у неё есть адрес

fwrite() читает адрес и с него переписывает байты в поток

Регистрация: 05.11.2010
Сообщений: 144
на сколько я понял должно быть что-то типа:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
struct BIN { unsigned long int msec; char array[512]; }; FILE* fp2 = fopen("C:\\rez.bin", "wb"); char randmass[512]; unsigned long int k; int i; struct BIN bin={k, randmass[512]}; for (k=all1; kall2; k+=step) { for (i=0; i512; i++) { randmass[i]=10.0*rand() / RAND_MAX; } fwrite (&bin,sizeof(bin), 1, fp2); // объясни плз смысл этой строчки, зачм нам знать размер структуры и причём тут цира 1? } fclose(fp2);

но всё равно что-то не так

Эксперт С++

5041 / 2620 / 241
Регистрация: 07.10.2009
Сообщений: 4,310
Записей в блоге: 1

Лучший ответ

Сообщение было отмечено Памирыч как решение

Решение

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
#include #define randarr_size typedef struct { unsigned long msec; char randarr[RANDARR_SIZE]; } REZ_BIN; int main() { REZ_BIN rbin; FILE *pfile = NULL; if((pfile = fopen("file.dat", "wb")) == NULL) { fprintf(stderr, "can't open file\n"); exit(1); } // . // . // . fwrite(&rbin, sizeof(rbin), 1, pfile); fclose(pfile); return 0; }

Добавлено через 7 минут
Функция fwrite имеет следующий прототип:

size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );

и выполняет запись блока данных в поток.

Запись блок из count элементов, каждый из которых имеет размер size байт, из блока памяти, на который указывает ptr, начиная с текущей позиции потока.
Таким образом общее количество записанных байт будет равно (size * count).

Теперь подробнее про параметры:
ptr — указатель на блок элементов для записи.
size — размер в байтах одного элемента
count — количество элементов
stream — указатель на файл (FILE *) или соответствующий поток вывода.

Функция возвращает количество успешно записанных элементов. Если возвращаемое значение не равно count, значит где-то в процессе записи произошла ошибка.

Параметры нужны для правильной организации работы функции.

Регистрация: 05.11.2010
Сообщений: 144
где у меня ошибка?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
///////////////////////// #include //вид nastr.cfg: // #include //date1 = 12.12.2010 // #include //date2 = 13.12.2010 // #include //time1 = 12:15:18:001 // #include //time2 = 15:12:22:101 // //step = 1000 // ///////////////////////// typedef struct{ unsigned long int msec; char randarr[512]; } REZ_BIN; int main() { srand((unsigned)(time(NULL))); clrscr(); FILE *fp; int day1, month1, year1; int day2, month2, year2; int hour1, min1, sec1, msec1; int hour2, min2, sec2, msec2; unsigned long int all1, all2; int step; if((fp=fopen("../etc/nastr.cfg", "r")) == NULL) { perror("net faila c nastroikami \n"); getch (); return(1); } fscanf(fp, "date1 = %2d.%2d.%4d""\n", &day1, &month1, &year1); fscanf(fp, "date2 = %2d.%2d.%4d""\n", &day2, &month2, &year2); fscanf(fp, "time1 = %2d:%2d:%2d:%3d""\n", &hour1, &min1, &sec1, &msec1); fscanf(fp, "time2 = %2d:%2d:%2d:%3d""\n", &hour2, &min2, &sec2, &msec2); fscanf(fp, "step = %d\n", &step); printf("date1 = %02d.%02d.%04d""\n", day1, month1, year1); printf("date2 = %02d.%02d.%04d""\n", day2, month2, year2); printf("time1 = %02d:%02d:%02d:%03d""\n", hour1, min1, sec1, msec1); printf("time2 = %02d:%02d:%02d:%03d""\n", hour2, min2, sec2, msec2); printf("step = %d\n", step); fclose(fp); all1 = (sec1*1000+min1*60000+hour1*3600000+msec1); all2 = (sec2*1000+min2*60000+hour2*3600000+msec2); printf("msec start = %lu\n",all1); printf("msec stop = %lu\n",all2); //////////////////////////////////////////////////////////////////////////// FILE* fp2 = fopen("../data/rez.bin", "wb"); char randmass[512]; unsigned long int k; int i; REZ_BIN rbin={k, randmass[512]}; for (k=all1; kall2; k+=step) { for (i=0; i512; i++) { randmass[i]=10.0*rand() / RAND_MAX; } fwrite (&rbin,sizeof(rbin), 1, fp2); // в бин файле должно быть время+ранд массив, снова время+массив. } fclose(fp2); getch(); return 0; }

Запись структуры в бинарный файл и чтение из него

Здравствуйте! Помогите решить проблему! У нас есть структура data_count, в которой хранятся полученные параметры файлов типа .doc. Бинарный файл должен являтся некой «базой данных», в котором должны хранится записи с этими параметрами.

struct data_count
long int W;
long int C;
long int Pg;
long int Par;
long int Ln;
long int CWS;
>;
data_count X[10000];

При каждом запуске программы мы открываем файл для определения количества записанных в него записей, и в последующую будем записывать структуру с новыми полученными параметрами.

//—получение количества записей в файле—————————

Далее делаем сверку новых полученных параметров с теми, которые уже записаны в файл. Если совпадающих параметров нет — записываем структуру с новыми данными в файл.

. MessageBox(NULL, «Файл успешно принят», «Статус проверки», MB_OKCANCEL);
X[quantity].W = WCount;
X[quantity].C = CCount;
X[quantity].Pg = PgCount;
X[quantity].Par = ParCount;
X[quantity].Ln = LnCount;
X[quantity].CWS = CWSCount;

Не пойму почему, но всё отлично работает только с первыми двумя записями: и проверяет, и сверяет, и пишет в файл. После получения параметров 3-го документа структра записывается на место второй записи в файле (переменная quantity получает значение 2, а не 3). Элемент X.W, уже записанной в бинарный файл структры, никогда не будет нулевым, т.к показывает количество слов в файле .doc (этот момент в программе предусмотрен). Помогите разобраться, как структуру с новыми полученными данными записать после последней записи в файле. заранее спасибо.

Бинарные файлы

Т екстовые файлы хранят данные в виде текста (sic!). Это значит, что если, например, мы записываем целое число 12345678 в файл, то записывается 8 символов, а это 8 байт данных, несмотря на то, что число помещается в целый тип. Кроме того, вывод и ввод данных является форматированным, то есть каждый раз, когда мы считываем число из файла или записываем в файл происходит трансформация числа в строку или обратно. Это затратные операции, которых можно избежать.

Текстовые файлы позволяют хранить информацию в виде, понятном для человека. Можно, однако, хранить данные непосредственно в бинарном виде. Для этих целей используются бинарные файлы.

#include #include #include #define ERROR_FILE_OPEN -3 void main() < FILE *output = NULL; int number; output = fopen("D:/c/output.bin", "wb"); if (output == NULL) < printf("Error opening file"); getch(); exit(ERROR_FILE_OPEN); >scanf("%d", &number); fwrite(&number, sizeof(int), 1, output); fclose(output); _getch(); >

Выполните программу и посмотрите содержимое файла output.bin. Число, которое ввёл пользователь записывается в файл непосредственно в бинарном виде. Можете открыть файл в любом редакторе, поддерживающем представление в шестнадцатеричном виде (Total Commander, Far) и убедиться в этом.

Запись в файл осуществляется с помощью функции

size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );

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

Запись в бинарный файл объекта похожа на его отображение: берутся данные из оперативной памяти и пишутся как есть. Для считывания используется функция fread

size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );

Функция возвращает число удачно прочитанных элементов, которые помещаются по адресу ptr. Всего считывается count элементов по size байт. Давайте теперь считаем наше число обратно в переменную.

#include #include #include #define ERROR_FILE_OPEN -3 void main() < FILE *input = NULL; int number; input = fopen("D:/c/output.bin", "rb"); if (input == NULL) < printf("Error opening file"); getch(); exit(ERROR_FILE_OPEN); >fread(&number, sizeof(int), 1, input); printf("%d", number); fclose(input); _getch(); >

fseek

Одной из важных функций для работы с бинарными файлами является функция fseek

int fseek ( FILE * stream, long int offset, int origin );

Эта функция устанавливает указатель позиции, ассоциированный с потоком, на новое положение. Индикатор позиции указывает, на каком месте в файле мы остановились. Когда мы открываем файл, позиция равна 0. Каждый раз, записывая байт данных, указатель позиции сдвигается на единицу вперёд.
fseek принимает в качестве аргументов указатель на поток и сдвиг в offset байт относительно origin. origin может принимать три значения

  • SEEK_SET — начало файла
  • SEEK_CUR — текущее положение файла
  • SEEK_END — конец файла. К сожалению, стандартом не определено, что такое конец файла, поэтому полагаться на эту функцию нельзя.

В случае удачной работы функция возвращает 0.

Дополним наш старый пример: запишем число, затем сдвинемся указатель на начало файла и прочитаем его.

#include #include #include #define ERROR_FILE_OPEN -3 void main() < FILE *iofile = NULL; int number; iofile = fopen("D:/c/output.bin", "w+b"); if (iofile == NULL) < printf("Error opening file"); getch(); exit(ERROR_FILE_OPEN); >scanf("%d", &number); fwrite(&number, sizeof(int), 1, iofile); fseek(iofile, 0, SEEK_SET); number = 0; fread(&number, sizeof(int), 1, iofile); printf("%d", number); fclose(iofile); _getch(); >

Вместо этого можно также использовать функцию rewind, которая перемещает индикатор позиции в начало.

В си определён специальный тип fpos_t, который используется для хранения позиции индикатора позиции в файле.
Функция

int fgetpos ( FILE * stream, fpos_t * pos );

используется для того, чтобы назначить переменной pos текущее положение. Функция

int fsetpos ( FILE * stream, const fpos_t * pos );

используется для перевода указателя в позицию, которая хранится в переменной pos. Обе функции в случае удачного завершения возвращают ноль.

long int ftell ( FILE * stream );

возвращает текущее положение индикатора относительно начала файла. Для бинарных файлов — это число байт, для текстовых не определено (если текстовый файл состоит из однобайтовых символов, то также число байт).

Рассмотрим пример: пользователь вводит числа. Первые 4 байта файла: целое, которое обозначает, сколько чисел было введено. После того, как пользователь прекращает вводить числа, мы перемещаемся в начало файла и записываем туда число введённых элементов.

#include #include #include #define ERROR_OPEN_FILE -3 void main() < FILE *iofile = NULL; unsigned counter = 0; int num; int yn; iofile = fopen("D:/c/numbers.bin", "w+b"); if (iofile == NULL) < printf("Error opening file"); getch(); exit(ERROR_OPEN_FILE); >fwrite(&counter, sizeof(int), 1, iofile); do < printf("enter new number? [1 - yes, 2 - no]"); scanf("%d", &yn); if (yn == 1) < scanf("%d", &num); fwrite(&num, sizeof(int), 1, iofile); counter++; >else < rewind(iofile); fwrite(&counter, sizeof(int), 1, iofile); break; >> while(1); fclose(iofile); getch(); >

Вторая программа сначала считывает количество записанных чисел, а потом считывает и выводит числа по порядку.

#include #include #include #define ERROR_OPEN_FILE -3 void main() < FILE *iofile = NULL; unsigned counter; int i, num; iofile = fopen("D:/c/numbers.bin", "rb"); if (iofile == NULL) < printf("Error opening file"); getch(); exit(ERROR_OPEN_FILE); >fread(&counter, sizeof(int), 1, iofile); for (i = 0; i < counter; i++) < fread(&num, sizeof(int), 1, iofile); printf("%d\n", num); >fclose(iofile); getch(); >

Примеры

1. Имеется бинарный файл размером 10*sizeof(int) байт. Пользователь вводит номер ячейки, после чего в неё записывает число. После каждой операции выводятся все числа. Сначала пытаемся открыть файл в режиме чтения и записи. Если это не удаётся, то пробуем создать файл, если удаётся создать файл, то повторяем попытку открыть файл для чтения и записи.

#include #include #include #define SIZE 10 void main() < const char filename[] = "D:/c/state"; FILE *bfile = NULL; int pos; int value = 0; int i; char wasCreated; do < wasCreated = 0; bfile = fopen(filename, "r+b"); if (NULL == bfile) < printf("Try to create file. \n"); getch(); bfile = fopen(filename, "wb"); if (bfile == NULL) < printf("Error when create file"); getch(); exit(1); >for (i = 0; i < SIZE; i++) < fwrite(&value, sizeof(int), 1, bfile); >printf("File created successfully. \n"); fclose(bfile); wasCreated = 1; > > while(wasCreated); do < printf("Enter position [0..9] "); scanf("%d", &pos); if (pos < 0 || pos >= SIZE) < break; >printf("Enter value "); scanf("%d", &value); fseek(bfile, pos*sizeof(int), SEEK_SET); fwrite(&value, sizeof(int), 1, bfile); rewind(bfile); for (i = 0; i < SIZE; i++) < fread(&value, sizeof(int), 1, bfile); printf("%d ", value); >printf("\n"); > while(1); fclose(bfile); >

2. Пишем слова в бинарный файл. Формат такой — сначало число букв, потом само слово без нулевого символа. Ели длина слова равна нулю, то больше слов нет. Сначала запрашиваем слова у пользователя, потом считываем обратно.

#include #include #include #include #define ERROR_FILE_OPEN -3 void main() < const char filename[] = "C:/c/words.bin"; const char termWord[] = "exit"; char buffer[128]; unsigned int len; FILE *wordsFile = NULL; printf("Opening file. \n"); wordsFile = fopen(filename, "w+b"); if (wordsFile == NULL) < printf("Error opening file"); getch(); exit(ERROR_FILE_OPEN); >printf("Enter words\n"); do < scanf("%127s", buffer); if (strcmp(buffer, termWord) == 0) < len = 0; fwrite(&len, sizeof(unsigned), 1, wordsFile); break; >len = strlen(buffer); fwrite(&len, sizeof(unsigned), 1, wordsFile); fwrite(buffer, 1, len, wordsFile); > while(1); printf("rewind and read words\n"); rewind(wordsFile); getch(); do < fread(&len, sizeof(int), 1, wordsFile); if (len == 0) < break; >fread(buffer, 1, len, wordsFile); buffer[len] = '\0'; printf("%s\n", buffer); > while(1); fclose(wordsFile); getch(); >

3. Задача — считать данные из текстового файла и записать их в бинарный. Для решения зачи создадим функцию обёртку. Она будет принимать имя файла, режим доступа, функцию, которую необходимо выполнить, если файл был удачно открыт и аргументы этой функции. Так как аргументов может быть много и они могут быть разного типа, то их можно передавать в качестве указателя на структуру. После выполнения функции файл закрывается. Таким образом, нет необходимости думать об освобождении ресурсов.

#include #include #include #define DEBUG #ifdef DEBUG #define debug(data) printf(«%s», data); #else #define debug(data) #endif const char inputFile[] = «D:/c/xinput.txt»; const char outputFile[] = «D:/c/output.bin»; struct someArgs < int* items; size_t number; >; int writeToFile(FILE *file, void* args) < size_t i; struct someArgs *data = (struct someArgs*) args; debug("write to file\n") fwrite(data->items, sizeof(int), data->number, file); debug(«write finished\n») return 0; > int readAndCallback(FILE *file, void* args) < struct someArgs data; size_t size, i = 0; int result; debug("read from file\n") fscanf(file, "%d", &size); data.items = (int*) malloc(size*sizeof(int)); data.number = size; while (!feof(file)) < fscanf(file, "%d", &data.items[i]); i++; >debug(«call withOpenFile\n») result = withOpenFile(outputFile, «w», writeToFile, &data); debug(«read finish\n») free(data.items); return result; > int doStuff() < return withOpenFile(inputFile, "r", readAndCallback, NULL); >//Обёртка — функция открывает файл. Если файл был благополучно открыт, //то вызывается функция fun. Так как аргументы могут быть самые разные, //то они передаются через указатель void*. В качестве типа аргумента //разумно использовать структуру int withOpenFile(const char *filename, const char *mode, int (*fun)(FILE* source, void* args), void* args) < FILE *file = fopen(filename, mode); int err; debug("try to open file ") debug(filename) debug("\n") if (file != NULL) < err = fun(file, args); >else < return 1; >debug(«close file «) debug(filename) debug(«\n») fclose(file); return err; > void main()

4. Функция saveInt32Array позволяет сохранить массив типа int32_t в файл. Обратная ей loadInt32Array считывает массив обратно. Функция loadInt32Array сначала инициализирует переданный ей массив, поэтому мы должны передавать указатель на указатель; кроме того, она записывает считанный размер массива в переданный параметр size, из-за чего он передаётся как указатель.

#include #include #include #include #define SIZE 100 int saveInt32Array(const char *filename, const int32_t *a, size_t size) < FILE *out = fopen(filename, "wb"); if (!out) < return 0; >//Записываем длину массива fwrite(&size, sizeof(size_t), 1, out); //Записываем весь массив fwrite(a, sizeof(int32_t), size, out); fclose(out); return 1; > int loadInt32Array(const char *filename, int32_t **a, size_t *size) < FILE *in = fopen(filename, "rb"); if (!in) < return 0; >//Считываем длину массива fread(size, sizeof(size_t), 1, in); //Инициализируем массив (*a) = (int32_t*) malloc(sizeof(int32_t) * (*size)); if (!(*a)) < return 0; >//Считываем весь массив fread((*a), sizeof(int32_t), *size, in); fclose(in); return 1; > void main() < const char *tmpFilename = "tmp.bin"; int32_t exOut[SIZE]; int32_t *exIn = NULL; size_t realSize; int i; for (i = 0; i < SIZE; i++) < exOut[i] = i*i; >saveInt32Array(tmpFilename, exOut, SIZE); loadInt32Array(tmpFilename, &exIn, &realSize); for (i = 0; i < realSize; i++) < printf("%d ", exIn[i]); >_getch(); >

5. Создание таблицы поиска. Для ускорения работы программы вместо вычисления функции можно произвести сначала вычисление значений функции на интервале с определённой точностью, после чего брать значения уже из таблицы. Программа сначала производит табулирование функции с заданными параметрами и сохраняет его в файл, затем подгружает предвычисленный массив, который уже используется для определения значений. В этой программе все функции возвращают переменную типа Result, которая хранит номер ошибки. Если функция отработала без проблем, то она возвращает Ok (0).

#define _CRT_SECURE_NO_WARNINGS //Да, это теперь обязательно добавлять, иначе не заработает #include #include #include #include #include //Каждая функция возвращает результат. Если он равен Ok, то функция //отработала без проблем typedef int Result; //Возможные результаты работы #define Ok 0 #define ERROR_OPENING_FILE 1 #define ERROR_OUT_OF_MEMORY 2 //Функция, которую мы будем табулировать double mySinus(double x) < return sin(x); >Result tabFunction(const char *filename, double from, double to, double step, double (*f)(double)) < Result r; FILE *out = fopen(filename, "wb"); double value; if (!out) < r = ERROR_OPENING_FILE; goto EXIT; >fwrite(&from, sizeof(from), 1, out); fwrite(&to, sizeof(to), 1, out); fwrite(&step, sizeof(step), 1, out); for (from; from < to; from += step) < value = f(from); fwrite(&value, sizeof(double), 1, out); >r = Ok; EXIT: fclose(out); return r; > Result loadFunction(const char *filename, double **a, double *from, double *to, double *step) < Result r; uintptr_t size; FILE *in = fopen(filename, "rb"); if (!in) < r = ERROR_OPENING_FILE; goto EXIT; >//Считываем вспомогательную информацию fread(from, sizeof(*from), 1, in); fread(to, sizeof(*to), 1, in); fread(step, sizeof(*step), 1, in); //Инициализируем массив size = (uintptr_t) ((*to - *from) / *step); (*a) = (double*) malloc(sizeof(double)* size); if (!(*a)) < r = ERROR_OUT_OF_MEMORY; goto EXIT; >//Считываем весь массив fread((*a), sizeof(double), size, in); r = Ok; EXIT: fclose(in); return r; > void main() < const char *tmpFilename = "tmp.bin"; Result r; double *exIn = NULL; int accuracy, option; double from, to, step, arg; uintptr_t index; //Запрашиваем параметры для создания таблицы поиска printf("Enter parameters\nfrom = "); scanf("%lf", &from); printf("to = "); scanf("%lf", &to); printf("step = "); scanf("%lf", &step); r = tabFunction(tmpFilename, from, to, step, mySinus); if (r != Ok) < goto CATCH_SAVE_FUNCTION; >//Обратите внимание на формат вывода. Точность определяется //во время работы программы. Формат * подставит значение точности, //взяв его из списка аргументов accuracy = (int) (-log10(step)); printf("function tabulated from %.*lf to %.*lf with accuracy %.*lf\n", accuracy, from, accuracy, to, accuracy, step); r = loadFunction(tmpFilename, &exIn, &from, &to, &step); if (r != Ok) < goto CATCH_LOAD_FUNCTION; >accuracy = (int)(-log10(step)); do < printf("1 to enter values, 0 to exit : "); scanf("%d", &option); if (option == 0) < break; >else if (option != 1) < continue; >printf("Enter value from %.*lf to %.*lf : ", accuracy, from, accuracy, to); scanf("%lf", &arg); if (arg < from || arg >to) < printf("bad value\n"); continue; >index = (uintptr_t) ((arg - from) / step); printf("saved %.*lf\ncomputed %.*lf\n", accuracy, exIn[index], accuracy, mySinus(arg)); > while (1); r = Ok; goto EXIT; CATCH_SAVE_FUNCTION: < printf("Error while saving values"); goto EXIT; >CATCH_LOAD_FUNCTION: < printf("Error while loading values"); goto EXIT; >EXIT: free(exIn); _getch(); exit(r); >

6. У нас имеются две структуры. Первая PersonKey хранит логин, пароль, id пользователя и поле offset. Вторая структура PersonInfo хранит имя и фамилию пользователя и его возраст. Первые структуры записываются в бинарный файл keys.bin, вторые структуры в бинарный файл values.bin. Поле offset определяет положение соответствующей информации о пользователе во втором файле. Таким образом, получив PersonKey из первого файла, по полю offset можно извлечь из второго файла связанную с данным ключом информацию.

Зачем так делать? Это выгодно в том случае, если структура PersonInfo имеет большой размер. Извлекать массив маленьких структур из файла не накладно, а когда нам понадобится большая структура, её можно извлечь по уже известному адресу в файле.

#define _CRT_SECURE_NO_WARNINGS #include #include #include #include typedef struct PersonKey < long long id; char login[64]; char password[64]; long offset;//Положение соответствующих значений PersonInfo >PersonKey; typedef struct PersonInfo < unsigned age; char firstName[64]; char lastName[128]; >PersonInfo; /* Функция запрашивает у пользователя данные и пишет их подряд в два файла */ void createOnePerson(FILE *keys, FILE *values) < static long long pkey; PersonInfo pinfo; pkey.id = id++; //Так как все значения пишутся друг за другом, то текущее положение //указателя во втором файле будет позицией для новой записи pkey.offset = ftell(values); printf("Login: "); scanf("%63s", pkey.login); printf("Password: "); scanf("%63s", pkey.password); printf("Age: "); scanf("%d", &(pinfo.age)); printf("First Name: "); scanf("%63s", pinfo.firstName); printf("Last Name: "); scanf("%127s", pinfo.lastName); fwrite(&pkey, sizeof(pkey), 1, keys); fwrite(&pinfo, sizeof(pinfo), 1, values); >void createPersons(FILE *keys, FILE *values) < char buffer[2]; int repeat = 1; int counter = 0;//Количество элементов в файле //Резервируем место под запись числа элементов fwrite(&counter, sizeof(counter), 1, keys); printf("CREATE PERSONS\n"); do < createOnePerson(keys, values); printf("\nYet another one? [y/n]"); scanf("%1s", buffer); counter++; if (buffer[0] != 'y' && buffer[0] != 'Y') < repeat = 0; >> while(repeat); //Возвращаемся в начало и пишем количество созданных элементов rewind(keys); fwrite(&counter, sizeof(counter), 1, keys); > /* Создаём массив ключей */ PersonKey* readKeys(FILE *keys, int *size) < int i; PersonKey *out = NULL; rewind(keys); fread(size, sizeof(*size), 1, keys); out = (PersonKey*) malloc(*size * sizeof(PersonKey)); fread(out, sizeof(PersonKey), *size, keys); return out; >/* Функция открывает сразу два файла. Чтобы упростить задачу, возвращаем массив файлов. */ FILE** openFiles(const char *keysFilename, const char *valuesFilename) < FILE **files = (FILE**)malloc(sizeof(FILE*)*2); files[0] = fopen(keysFilename, "w+b"); if (!files[0]) < return NULL; >files[1] = fopen(valuesFilename, "w+b"); if (!files[1]) < fclose(files[0]); return NULL; >return files; > /* Две вспомогательные функции для вывода ключа и информации */ void printKey(PersonKey pk) < printf("%d. %s [%s]\n", (int)pk.id, pk.login, pk.password); >void printInfo(PersonInfo info) < printf("%d %s %s\n", info.age, info.firstName, info.lastName); >/* Функция по ключу (вернее, по его полю offset) достаёт нужное значение из второго файла */ PersonInfo readInfoByPersonKey(PersonKey pk, FILE *values) < PersonInfo out; rewind(values); fseek(values, pk.offset, SEEK_SET); fread(&out, sizeof(PersonInfo), 1, values); return out; >void getPersonsInfo(PersonKey *keys, FILE *values, int size) < int index; PersonInfo p; do < printf("Enter position of element. To exit print bad index: "); scanf("%d", &index); if (index < 0 || index >= size) < printf("Bad index"); return; >p = readInfoByPersonKey(keys[index], values); printInfo(p); > while (1); > void main() < int size; int i; PersonKey *keys = NULL; FILE **files = openFiles("C:/c/keys.bin", "C:/c/values.bin"); if (files == 0) < printf("Error opening files"); goto FREE; >createPersons(files[0], files[1]); keys = readKeys(files[0], &size); for (i = 0; i < size; i++) < printKey(keys[i]); >getPersonsInfo(keys, files[1], size); fclose(files[0]); fclose(files[1]); FREE: free(files); free(keys); _getch(); >

ru-Cyrl 18- tutorial Sypachev S.S. 1989-04-14 sypachev_s_s@mail.ru Stepan Sypachev students

email

Всё ещё не понятно? – пиши вопросы на ящик

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *