База данных на файлах: запись с уникальным идентификатором
Задача: разработать на C++ справочно-информационную систему, в базу данных которой (в файле) данные записываются с уникальным идентификационным номером (ID). Вариант с ручным внесением идентификационного номера исключается как неуважительный к пользователю. Да и запутаться легко, внося ID вручную.
Сложность задачи вызвана тем, что данные из базы могут быть удалены, а идентификационные номера сохранённых записей остаются прежними. Поэтому идентификационный номер каждой новой записи должен представлять собой не увеличенное на единицу число элементов массива, а увеличенный на единицу идентификационный номер последней записи данной структуры.
Пусть требуется разработать справочно-информационную систему библиотеки. Создаём структуры с данными о книгах в фонде, книгах в выдаче, читателях и библиотекарях. Данные структуры должны записываться в файл, в каждой структуре есть данные идентификационного номера (ID). Есть два уровня пользователя. Первый - читатель, который может просматривать данные о книгах в фонде. Второй - библиотекарь, он же администратор, который может просматривать все данные, а также вносить новые данные и редактировать уже содержащиеся в базе.
Рассмотрим подробнее, как реализуется запись даннных с уникальным идентификационным номером. Наиболее важны два момента.
1. Происходит открытие файла данных о читателях. Данные считываются из файла. Из вновь созданного массива принимаются данные о номере идентификатора читалеля. Если этот номер превышает количество элементов (записях о читателях), то данные о новом читателе в базу данных записываются с номером, на 1 больше последнего номера из базы данных. Если не превышает, то номер присваивается на единицу больше числа элементов массива (читателей).
Код C++
Reader* reader_arr = new Reader[n];
FILE * ff;
int b = 0;
int c = 0;
fstream fs;
fs.open ("Reader.dat");
if (fs.is_open())
{
ff = fopen("Reader.dat","rb");
int fsize;
fseek(ff,0,SEEK_END);
fsize = ftell(ff);
b = fsize / sizeof(Reader);
Reader* start_arr2 = new Reader[b]; //создаётся новый массив из данных структуры
fseek(ff,0,SEEK_SET);
fread(start_arr2,sizeof(Reader),b,ff);
c = start_arr2[b - 1].id + 1; //присваиваются данные об ID последней записи масссива
fclose( ff);
fs.close();
}
for (int i = 0; i < n; i++)
{
if (c >= b)
reader_arr[i].id = c + i;
else
reader_arr[i].id = b + i;
cout << "Enter name and surname: "; //далее записываются все
cin.getline(reader_arr[i].name_surname, 30); //необходимые данные о читателях
cout << "Enter day of birth: ";
cin >> reader_arr[i].birth_date.date;
cout << "Enter month of birth: ";
cin >> reader_arr[i].birth_date.month;
cout << "Enter year of birth: ";
cin >> reader_arr[i].birth_date.year;
cin.get();
cout << "Enter profession: ";
cin.getline(reader_arr[i].profession, 20);
cout << "Enter education: ";
cin.getline(reader_arr[i].education, 16);
cout << "Enter address: ";
cin.getline(reader_arr[i].address, 50);
cout << "Enter phone: ";
cin >> reader_arr[i].phone;
cin.get();
cout << endl;
}
ff = fopen("Reader.dat","a");
fwrite(reader_arr,sizeof(Reader),n,ff); //все внесённые данные записываются
fclose( ff);
2. Точно так же, как данные о читателях, в базу данных записываются данные о библиотекарях. Подводный камень нашей программы кроется в том, что библиотекари имеют доступ к информационной системе с паролем. При выборе библиотекарем пункта меню, извещающего программу о том, что он хочет войти в систему как библиотекарь, открывается файл данных о библиотекарях. И тут... Если библиотекарь в течении сессии будет редактировать данные о библиотекарях (так же, как и о читателях), то файл, открытый при входе в систему, будет продолжать оставаться открытым и данные в базу не запишутся. Для этого предусмотрено закрытие файла данных о библиотекарях после прочтения имени пользователя и пароля вошедшего в систему.
Код C++
if (t == 2)
{
int b;
int count1 = 0;
int count2 = 0;
char Slogin[16];
char Spassw[16];
cout << "Enter login: ";
cin >> Slogin;
cin.get();
FILE * fn;
fn = fopen("Lib.dat","rb");
int fsize;
fseek(fn,0,SEEK_END);
fsize = ftell(fn);
b = fsize / sizeof(Librarian);
Librarian* librarian_arr2 = new Librarian[b];
fseek(fn,0,SEEK_SET);
fread(librarian_arr2,sizeof(Librarian),b,fn);
fclose(fn);
for (int i = 0; i < b; i++)
{
while (strstr(librarian_arr2[i].login, Slogin))
{
cout << "Enter password: ";
cin >> Spassw;
while (strstr(librarian_arr2[i].password, Spassw))
{
menu();
count2++;
break;
}
count1++;
break;
}
}
Внимание! Закрытие файла с данными о библиотекарях должно произойти сразу же после считывания массива данных о библиотекарях. Если задать закрыте ниже, например, после кода, отвечающего за ввод и приём данных логина и пароля, то файл уже при внесении или редактировании данных о библиотекарях будет открытым и новые данные в него не запишутся.