МІНІСТЕРСТВО ОСВІТИ УКРАЇНИ
Національний університет “Львівська політехніка”
Кафедра САПР
Лабораторна робота № 3
«ІНДЕКСНО-ПОСЛІДОВНИЙ МЕТОД ДОСТУПУ ДО ФАЙЛІВ НА ЗОВНІШНІХ ЗАПАМ’ЯТОВУЮЧИХ ПРИСТРОЯХ»
з курсу “ Організація баз даних і знань ”
МЕТА РОБОТИ
Розглянути органiзацiю i ведення файлiв iндексно-послiдовного доступу; набути практичнi навички у програмуваннi алгоритмiв iндексно-послiдовного доступу до файлiв на зовнiшнiх запам'ятовуючих пристроях.
2. КОРОТКІ ТЕОРЕТИЧНІ ВІДОМОСТІ
Якщо файл впорядкований по ключах, то звичайно для адресацiї використовується таблиця, що називається iндексом. При звертаннi до таблицi задається ключ шуканого запису, а результатом процедури пошуку у таблицi є вiдносна адреса запису у зовнiшнiй пам'ятi.
Якщо для адресацiї файла використовується iндекс, ЕОМ в основному здiйснює пошук в iндексi, а не у файлi даних. При цьому суттєво економиться час, але потребується пам'ять для зберiгання iндексу.
Існує багато iндексних методiв доступу, в основi яких лежить принцип створення окремого iндексного файла. індексний файл значно менший вiд власне бази даних, i, оскiльки вiн може повнiстю зберiгатися в оперативнiй пам'ятi, швидкодiя пошуку у ньому значно вища.
В iндексно-послiдовному методi доступу iндексний файл завжди впорядкований за так званим первинним ключем (головний атрибут фiзичного запису).
Оскiльки у цьому методi i записи файла даних впорядкованi за ключем, iндекс звичайно мiстить не посилання на окремий запис, а посилання на блоки записiв, всерединi яких можна здiйснювати пошук i сканування. Збереження посилань на блоки записiв, а не на окремi записи значно зменшує розмiр iндексу. Наприклад, якщо в блоцi зберiгається 10 записiв, то для нього в iндексному файлi буде одна стаття, а не 10, i розмiр iндексного файла зменшується в 10 разiв.
Значення дійсного ключа
Адресний номер блока
745
867
899
1
2
3
Рис.1 Блокова органiзацiя файла даних при iндексно-послiдовному методi доступу.
Індексний файл i файл даних органiзованi послiдовно. Індексний файл мiстить лише максимальнi значення первинних ключiв записiв кожного блока.
Послiдовна органiзацiя індексного файла допускає iндексацiю його вмiсту. Записи iндексу групуються у блоки, якi можна iндексувати. Індексний файл наступного рiвня мiстить вказiвники на індекснi файли попереднього рiвня.
При роботi з великими файлами така органiзацiя дає змогу покращити характеристики доступу.
Індексний файл складається з пар (значення ключа, адреса блока). Пара (v,b) з'являється у файлi iндексу, якщо перший запис у блоцi з адресою b має значення ключа v. Перше поле є ключем файла iндексу, який пiдтримується вiдсортованим за значенням свого ключа.
Рис.2 Багатоiєрархiчна iндексацiя при iндексно-послiдовному методi доступу.
В iндексно-послiдовному файлi необхiдно отримати вiдповiдi на запитання: якщо задане значення ключа v1 для iндексного файла, знайти в iндексi такий запис (v2,b), що v2<=v1 i або (v2,b) ї останнiм записом у iндексi, або наступний запис (v3,b) задовольняє умову v1<v3. У цiй ситуацiї говорять, що v2 покриває v1. Отже, ми знаходимо блок b головного файла, що мiстить запис iз значенням ключа v1, оскiльки файл iндексу з гарантiїю є вiдсортованим.
2.1. ПОШУК В ІНДЕКСІ
Нехай є файл iндексу i необхiдно знайти запис (v2,b), такий, що v2 покриває задане значення ключа v1. Одна iз стратегiй полягає у використаннi лiнiйного пошуку, при якому переглядаються всi записи iндексу вiд самого початку доти, поки не буде знайдено запис, що покриває v1. Цей метод доцiльно використовувати лише для невеликих iндексiв. Краща стратегiя - використання двiйкового пошуку.
2.2. ВЕДЕННЯ ФАЙЛА ДАНИХ
Пiд час вставляння нових записiв виникає необхiднiсть або пересортовувати файл, або вносити новi записи в окрему дiлянку i органiзувати вказiвники на цi записи.
Цi записи помiщаються у дiлянку переповнення. Такi файли перiодично реорганiзовуються, т.б. записи файла заново сортуються i здiйснюються вiдповiднi змiни в iндексi.
Для уникнення частого використання процедури реорганiзацiї у файлi передбачаються позицiї з порожнiми записами (подiл файла даних на блоки). Але даний метод не дає змоги повнiстю уникнути виконання процедури реорганiзацiї.
Розглянемо операцiї пошуку, вставляння, видалення i модифiкацiї над вiдсортованим файлом iз записами, не закрiпленими вказiвниками за фіксованими адресами. Цi 4-и операцiї потребують вставляння, видалення, модифiкацiї у файлi iндексу.
Вхiдний вiдсортований файл мiститься у послiдовностi блокiв b1, b2,...,bk. Записи у кожному блоцi мiстяться у сортованоiй послiдовностi, причому записи блока bi передують записам блока bi+1. У заголовку кожного блока знаходиться iнформацiя, що вказує, який iз субблокiв мiстить записи, а який є вiльним.
2.2.1. ПОШУК
Потрiбно знайти у файлi даних запис iз значенням ключа v1. Спочатку знаходимо у файлi iндексу блок, перший запис якого мiстить значення ключа v2, такого, що v2 покриває v1. Здiйснюємо у цьому блоцi пошук запису з ключем v1.
Ми можемо випадково полiпшити вiльний блок i вирiшити, що вiн мiстить запис з ключем v1. Щоб цього не сталося, необхiдно перевiрити ознаку заголовка блоку.
2.2.2. ВСТАВЛЯННЯ
З метою вставляння запису iз значенням ключа v1 використаємо процедуру пошуку, щоб знайти блок bi, у якому мав би знаходитися такий запис. Розмiстимо новий запис у вiдповiдне мiсце у блоцi bi, зберiгши сортовану послiдовнiсть порядок i перемiстивши праворуч записи iз значенням ключа, бiльшим нiж v1, щоб звiльнити мiсце для нового запису. Якщо у блоцi b1 присутнiй хоча б один вiльний субблок у нього помiстяться всi записи. Якщо v1 передує значенню ключа v2 першого запису bi, необхiдно модифiкувати статтю файла iндекса для блока bi, використовуючи модифiкацiю, i змiнити iнформацiю “заповнений/незаповнений" у заголовку блока.
Припустимо, що блок bi вже заповнений настiльки, що для нового запису немає мiсця. Можливi стратегiї вирiшення: органiзацiя блока переповнення, розщеплення блока на два напiвпорожнi блоки.
2.2.3. МОДИФІКАЦІЯ
Для модифiкацiї запису iз значенням ключа v1 спочатку використовується процедура пошуку для цього запису. Якщо модифiкацiя змiнюї ключ, це iнтерпретується як його видалення з наступним вставленням. інакше здiйснюється модифiкацiя i перезаписується даний запис.
2.2.4. ВИДАЛЕННЯ
Як i пiд час вставлення запису, у даному випадку iснує кiлька стратегiй. (Наприклад, iснує стратегiя, яка не допускає присутностi блокiв, заповнених менше нiж наполовину.) Розглянемо стратегiю, що використовується для невеликої кiлькостi видалень.
Для видалення запису iз значенням ключа v1 використовуємо спочатку процедуру пошуку, щоб знайти цей запис. Перемiщаємо всi записи праворуч вiд нього на один субблок лiворуч для лiквiдацiї промiжку i приводимо у порядок показник "заповнений/незаповнений" у заголовку. Якщо блок став вiльним, видаляємо запис для даного блока в iндексi за допомогою стратегiї видалення.
Якщо блок пiсля видалення запису iз значенням ключа v1 залишається непорожнiм, то операцiю можна вважати закiнченою за умови, що видалений запис не був першим у блоцi. інакше потрiбно модифiкувати запис iндексу для цього блока.
ІНДИВІДУАЛЬНЕ ЗАВДАННЯ
Написати програму методу зв'язаних записiв, яка реалiзує такi функцiї:
1. Друк бази даних.
2. Зчитування запису.
3. Введення запису.
4. Видалення запису.
5. Модифiкацiя запису.
ТЕКСТ ПРОГРАМИ:
Вміст файлу MAIN.CPP
// include all the declarations
#include "D:\lab3\DECL.CPP"
// Global Variables
char FileNameDB [FILENAME_LENGTH];
char IndexFile [FILENAME_LENGTH];
char BufferFileName [FILENAME_LENGTH];
int RecordSize = sizeof(struct Record) + NUMBER_OF_FIELDS_IN_RECORD * sizeof(char); // symbols ' '
long BlockSize = RecordSize * BLOCK_SIZE;
void main (void)
{
clrscr();
printf("Insert filename of DataBase\n");
gets(FileNameDB);
printf("\nInsert filename of Index file\n");
gets(IndexFile);
getcwd(BufferFileName, FILENAME_LENGTH);
strcat(BufferFileName, "\\buffer.txt");
// create files if they has not been created
FILE * file = fopen(FileNameDB, "a+");
fclose(file);
file = fopen(IndexFile, "a+");
fclose(file);
// begin menu
int answer;
int Key = 1;
Action action;
while(Key)
{
// show the main menu
printf("\n%d - Insert", Insert);
printf("\n%d - Modify", Modify);
printf("\n%d - Delete", Delete);
printf("\n%d - Show fileBD", ShowDB);
printf("\n%d - Find record", Find);
printf("\n%d - Exit\n", Exit);
scanf("%d", &answer);
switch(answer)
{
case Insert:{
printf("\nInsert");
Record record = createRecord();
simpleInsert(record);
break;
};
case Modify:{
printf("\nModify");
FILE * sourceFile = fopen(FileNameDB,"r+");
printf("\nEnter number of Application of Record you want to modify ");
int number;
scanf("%d", &number);
long pointer = findRecord(sourceFile, number);
if ( pointer == -1 )
{
printf("\nRecord not found");
}
else
{
fseek(sourceFile, pointer, SEEK_SET);
Record rec = readRecord(sourceFile);
printf("\nHere is your old record");
displayRecord( rec );
simpleDelete( number );
printf("\n");
Record newRecord = createRecord();
while( newRecord.numberOfApplication != rec.numberOfApplication )
{
printf("\nYou entered wrong numerOfApplication\nTry one more time\n\n");
newRecord = createRecord();
}
simpleInsert(newRecord);
}
fclose(sourceFile);
break;
};
case Delete:{
printf("\nDelete");
printf("\nEnter number of application of that record which you want to delete ");
int number;
scanf("%d", &number);
simpleDelete(number);
break;
};
case ShowDB:
{
showDB();
break;
};
case Exit:
{
Key = 0;
break;
};
case Find:
{
FILE * file = fopen(FileNameDB ,"r");
printf("\nEnter number of Application you want to find ");
int number;
scanf("%d", &number);
Record foundRecord;
long address = findRecord(file, number);
fseek(file, address, SEEK_SET);
foundRecord = readRecord(file);
if ( address != -1 )
{
displayRecord( foundRecord );
}
else
{
printf("\nRecord not found");
}
fclose( file );
printf("\nPress any key to continue... \n");
getch();
break;
};
case NOP:
{
break;
};
default : Key = NOP;
}
}
getch();
}
Вміст файлу BASIC.CPP
// variables
extern char FileNameDB [];
extern char IndexFile [];
extern long BlockSize;
extern int RecordSize;
// basics functions which are used by other functions
// here are functions for write, read, find Record and others
// -----basic methods----
void showDB()
{
FILE * source = fopen(FileNameDB, "r");
FILE * index = fopen(IndexFile, "r");
long address;
int maxKey = 0;
while (feof(index) == 0)
{
fscanf(index, "%d", &maxKey);
fscanf(index, "%ld\n", &address);
// display all the records in this block
fseek(source, address + 3 + OFFSET_IN_CAPTION, SEEK_SET);
while( getc(source) != 0 )
{
fseek(source, ftell(source) - 1, SEEK_SET);
displayRecord(readRecord(source));
fseek(source, 1L, SEEK_CUR);
printf("\n Press 'Enter' to continue...");
getch();
}
}
fclose(source);
fclose(index);
}
void writeRecord(FILE * filepointer, Record record)
{
fprintf(filepointer, "\n%d ", record.numberOfApplication);
fprintf(filepointer, "%d ", record.person);
fprintf(filepointer, "%s ", record.name);
fprintf(filepointer, "%s ", record.surname);
fprintf(filepointer, "%s ", record.adress);
fprintf(filepointer, "%s ", record.telnumber);
fprintf(filepointer, "%s ", record.rick);
fprintf(filepointer, "%s ", record.vartist);
fprintf(filepointer, "%s ", record.nazva);
fprintf(filepointer, "%s ", record.wanr);
fprintf(filepointer, "%s", record.sponsor);
}
void displayRecord(Record pointer)
{
printf("\nNumberInList: %d ", pointer.numberOfApplication);
printf("\nSex : %s ", ((pointer.person == Male)?"Male":"Female"));
printf("\nName :%s ", pointer.name);
printf("\nSurname: %s ", pointer.surname);
printf("\nadress: %s ", pointer.adress);
printf("\ntelnumber number: %s ", pointer.telnumber);
printf("\nrick: %s ", pointer.rick);
printf("\nvartist: %s ", pointer.vartist);
printf("\nnazva: %s ", pointer.nazva);
printf("\nwanr: %s ", pointer.wanr);
printf("\nsponsor: %s", pointer.sponsor);
}
Record readRecord(FILE * filepointer)
{
Record buffer;
// reading data from file
fscanf(filepointer, "\n%d", &(buffer.numberOfApplication));
fscanf(filepointer, "%d", &(buffer.person));
fscanf(filepointer, "%s", buffer.name);
fscanf(filepointer, "%s", buffer.surname);
fscanf(filepointer, "%s", buffer.adress);
fscanf(filepointer, "%s", buffer.telnumber);
fscanf(filepointer, "%s", &(buffer.rick));
fscanf(filepointer, "%s", &(buffer.vartist));
fscanf(filepointer, "%s", buffer.nazva);
fscanf(filepointer, "%s", buffer.wanr);
fscanf(filepointer, "%s", buffer.sponsor);
return buffer;
}
long findRecord(FILE * file, int numberOfApplication)
{
FILE * index = fopen(IndexFile, "r");
long blockAddress;
int maxKey = 0;
while ((maxKey < numberOfApplication) && (feof(index) == 0))
{
fscanf(index, "%d", &maxKey);
fscanf(index, "%ld\n", &blockAddress);
}
fseek(file, blockAddress + 3 + OFFSET_IN_CAPTION, SEEK_SET);
static Record rec;
long recordAddress;
int i = 0;
while ( getc(file) != 0 )
{
fseek(file, ftell(file)-1, SEEK_SET);
recordAddress = ftell(file);
rec = readRecord(file);
if ( rec.numberOfApplication == numberOfApplication )
{
return recordAddress;
}
if ( i == BLOCK_SIZE )
{
break;
}
else
{
i++;
}
}
return -1;
}
Record createRecord()
{
Record record;
printf("\nLet's create the record");
printf("\nEnter NumberInList ");
scanf("%d", &(record.numberOfApplication));
printf("Enter sex (0 - Male, 1 - Female) ");
scanf("%d", &record.person);
printf("Enter name of hudownuk ");
scanf("%s", record.name);
printf("Enter surname of hudownuk ");
scanf("%s", record.surname);
printf("Enter adress of vustavka ");
scanf("%s", record.adress);
printf("Enter telefon number of vustavka ");
scanf("%s", record.telnumber);
printf("Enter rick of napusannj kartunu ");
scanf("%s", &(record.rick));
printf("Enter vartist of kartunu ");
scanf("%s", &(record.vartist));
printf("Enter nazva of the kartunu ");
scanf(" %s", record.nazva);
printf("Enter wanr of kartunu ");
scanf(" %s", record.wanr);
printf("Enter of sponsor ");
scanf(" %s", record.sponsor);
return record;
}
Вміст файлу DECL.CPP
#include <stdio.h>
#include <conio.h>
#include <ctype.h>
#include <dir.h>
#include <string.h>
#include <stdlib.h>
#define FILENAME_LENGTH 70
#define NAME_LENGTH 15
#define TEL_NUMBER_LENGTH 15
#define adress_LENGTH 20
#define OTHER_INF_LENGTH 11
#define BLOCK_SIZE 5 // size of block, doesn't matter which (overflow or ordinary)
// indicators
#define NO_FREE_SPACE 3 // no free space in overflow block
#define FREE_SPACE_IS 2 // there is free space in overflow block
#define EMPTY_BLOCK 1 // block is empty
#define OFFSET_IN_CAPTION 4
#define NUMBER_OF_FIELDS_IN_RECORD 12
// ==========DATA STRUCTURES============
enum Person
{
Male, Female
};
enum Action
{
Insert, Modify, Delete, Find, GoBack, Exit, Save, NOP ,ShowDB
};
struct Record
{
int numberOfApplication;
// hudownuk
Person person;
char name [NAME_LENGTH];
char surname [NAME_LENGTH];
char adress [adress_LENGTH];
char telnumber [TEL_NUMBER_LENGTH];
char rick [NAME_LENGTH];
char vartist [NAME_LENGTH];
char nazva [OTHER_INF_LENGTH];
char wanr [OTHER_INF_LENGTH];
char sponsor [FILENAME_LENGTH];
};
// ------ PROTOTYPES --------
// basic methods
void showDB(void);
void writeRecord(FILE * , Record);
void displayRecord(Record);
Record readRecord(FILE * );
long findRecord(FILE * , int );
Record createRecord(void);
Record createNullRecord();
// other Methods
void handleOverflow(long );
void insertRecordInBlock(Record , long , FILE * );
void clearBlock(long , FILE * );
void organizeIndex(char []);
long createBlock(FILE * );
void simpleInsert(Record);
void simpleDelete(int);
void simpleModify(Record);
// including files
#include "D:\Lab3\BASIC.CPP"
#include "D:\Lab3\WORK.CPP"
Вміст файлу WORK.CPP
// Global Variables
extern char FileNameDB [FILENAME_LENGTH];
extern char IndexFile [FILENAME_LENGTH];
extern char BufferFileName [FILENAME_LENGTH];
extern int RecordSize;
void simpleInsert(Record record)
{
FILE * file = fopen( FileNameDB, "r+");
if ( getc(file) == EOF )
{
// if the data base file is empty
fseek(file, 0L, SEEK_SET);
long address = createBlock(file);
fseek(file, address, SEEK_SET);
writeRecord(file, record);
fseek(file, 0L, SEEK_SET);
fprintf(file, "%d ", FREE_SPACE_IS);
fprintf(file, "%d", record.numberOfApplication);
fclose(file);
organizeIndex(FileNameDB);
}
else
{
fseek(file, 0L, SEEK_SET);
FILE * index = fopen(IndexFile, "r");
long address;
int maxKey = 0;
while ((maxKey < record.numberOfApplication) && (feof(index) == 0))
{
fscanf(index, "%d", &maxKey);
fscanf(index, "%ld\n", &address);
}
fclose( index );
fseek(file, address, SEEK_SET);
int indicator;
fscanf(file, "%d", &indicator);
if (indicator != NO_FREE_SPACE)
{
insertRecordInBlock(record, address, file);
}
else
{
if (indicator == NO_FREE_SPACE)
{
fclose(file);
handleOverflow(address);
organizeIndex(FileNameDB);
simpleInsert(record);
}
else
{
fclose( file );
}
}
organizeIndex(FileNameDB);
}
}
void simpleDelete(int numberOfApplication)
{
Record arrayOfRecords [BLOCK_SIZE];
FILE * file = fopen(FileNameDB, "r+");
FILE * index = fopen(IndexFile, "r");
int maxKey = 0;
long address;
while ((maxKey < numberOfApplication) && (feof(index) == 0))
{
fscanf(index, "%d", &maxKey);
fscanf(index, "%ld\n", &address);
}
fclose( index );
fseek( file, address + 3 + OFFSET_IN_CAPTION, SEEK_SET );
int i = 0;
while (getc(file) != 0)
{
fseek(file, ftell(file)-1, SEEK_SET);
arrayOfRecords[i] = readRecord(file);
fseek(file, 1, SEEK_CUR);
if ( i == BLOCK_SIZE )
{
break;
}
i++;
}
clearBlock(address, file);
fseek( file, address + 3 + OFFSET_IN_CAPTION, SEEK_SET );
int k = 0;
while( i > 0 )
{
if ( arrayOfRecords[k].numberOfApplication != numberOfApplication )
{
writeRecord(file, arrayOfRecords[k]);
}
k++;
i--;
}
fclose( file );
}
long createBlock(FILE * file)
{
fseek(file, 0L, SEEK_END);
fprintf(file, "%d ", FREE_SPACE_IS);
long curAddr = ftell(file);
fprintf(file, "%d", 0); // maxKey (by defaul) = 0
fseek(file, curAddr + 1 + OFFSET_IN_CAPTION + BlockSize, SEEK_SET);
fprintf(file, "%c", ' ');
return curAddr + 1 + OFFSET_IN_CAPTION;
}
void organizeIndex(char name [FILENAME_LENGTH])
{
FILE * data = fopen(name, "r");
FILE * index = fopen(IndexFile, "w");
fseek(data, 0L, SEEK_SET);
int indicator;
int maxKey;
long curAddr;
long beginAddress;
while (getc(data) != EOF)
{
fseek(data, ftell(data)-1, SEEK_SET);
beginAddress = ftell(data);
fscanf(data, "%d", &indicator);
curAddr = ftell( data );
fscanf(data, "%d", &maxKey);
fprintf(index, "%d %ld\n", maxKey, beginAddress);
fseek(data, curAddr + 3/*number of whitespaces*/ + OFFSET_IN_CAPTION + BlockSize, SEEK_SET);
}
fclose(index);
}
void insertRecordInBlock(Record record, long blockAddress, FILE * file)
{
long beginAddress = blockAddress + 3 + OFFSET_IN_CAPTION;
fseek(file, beginAddress, SEEK_SET);
Record mas [BLOCK_SIZE];
int i;
for (i = 0; i < BLOCK_SIZE; i++)
{
mas[i].numberOfApplication = -1;
}
long address;
i = 0;
int overflow = 0;
while (getc(file) != 0)
{
fseek(file, ftell(file)-1, SEEK_SET);
address = ftell(file);
mas[i] = readRecord( file );
if (i == BLOCK_SIZE-1)
{
overflow = 1;
break;
}
i++;
fseek(file, 1, SEEK_CUR);
}
if (overflow == 0) // if there wasn't overflow
{
clearBlock(blockAddress, file);
// set the filepointer to begin
fseek(file, beginAddress, SEEK_SET);
int key = 0;
for (i = 0 ; i < BLOCK_SIZE; i++)
{
if ( mas[i].numberOfApplication != -1 )
{
if ( (record.numberOfApplication < mas[i].numberOfApplication) && (key == 0) )
{
writeRecord(file, record);
writeRecord(file, mas[i]);
key = 1;
}
else
{
writeRecord(file, mas[i]);
}
}
}
if (key == 0)
{
writeRecord(file, record);
}
fseek(file, blockAddress + 2, SEEK_SET);
int maxKey;
fscanf(file, "%d", &maxKey);
if ( maxKey < record.numberOfApplication )
{
fseek(file, blockAddress + 2, SEEK_SET);
fprintf(file, "%d", record.numberOfApplication);
}
}
else
{
fseek(file, blockAddress, SEEK_SET);
fprintf(file, "%d ", NO_FREE_SPACE);
fclose(file);
simpleInsert(record);
}
fclose(file);
}
void clearBlock(long blockAddress, FILE * file)
{
long beginAddress = blockAddress + 2 + OFFSET_IN_CAPTION;
fseek(file, beginAddress, SEEK_SET);
for (int i = 0; i < BlockSize; i++)
{
putc(0, file);
}
}
void handleOverflow(long blockAddress)
{
FILE * source = fopen(FileNameDB, "r");
FILE * buffer = fopen(BufferFileName, "w");
fseek(source, 0L, SEEK_SET);
int c;
Record bufRec;
// copying those blokcs which store before overflowed block
while(ftell(source) < blockAddress)
{
c = fgetc( source );
fputc(c, buffer);
}
// create ang write first newblock
long beginAddress = createBlock(buffer);
fseek(buffer, beginAddress, SEEK_SET);
fseek(source, beginAddress, SEEK_SET);
for (c = 0; c < BLOCK_SIZE/2 + 1; c++)
{
bufRec = readRecord(source);
writeRecord(buffer, bufRec);
}
fseek(buffer, blockAddress, SEEK_SET);
fprintf(buffer, "%d %d", FREE_SPACE_IS, bufRec.numberOfApplication);
// create ang write second newblock
beginAddress = createBlock(buffer);
fseek(buffer, beginAddress, SEEK_SET);
for (c = 0; c < BLOCK_SIZE - BLOCK_SIZE/2 - 1; c++)
{
bufRec = readRecord(source);
writeRecord(buffer, bufRec);
}
fseek(buffer, beginAddress - 3 - OFFSET_IN_CAPTION, SEEK_SET);
fprintf(buffer, "%d %d", FREE_SPACE_IS, bufRec.numberOfApplication);
fclose(buffer);
buffer = fopen(BufferFileName, "a");
// copying those blokcs which store after overflowed block
fseek(source, blockAddress + BlockSize + 4 + OFFSET_IN_CAPTION, SEEK_SET);
while ((c = getc(source)) != EOF)
{
fputc(c, buffer);
}
fclose(buffer);
fclose(source);
// remove source file and rename targetFile
remove(FileNameDB);
rename(BufferFileName, FileNameDB);
}
Результати роботи програми
При запуску програми користувачу пропонується ввести повну назву файлу, де буде або вже зберігається база даних та назву індексного файлу. Далі виводиться головне меню, яке виглядає наступним чином.
При натиснені «5» відбувається вихід з програми.
При натиснені «3» можна здійснити пошук запису в базі даних за введеним значення ключа.
При натиснені «8» програма по одному запису виводить всі записи, що містяться в базі данних.
При натисненні «0» виведеться меню для введення запису.
При натисненні «1» буде виведено старий запис та буде виведено меню для введеня нового запису.
При натисненні «2» виведеться на дисплей прохання ввести номер запису, який слід видалити.
Приклад файлу бази даних
2 3
1 0 Ivan Ayvazovski Lviv 9546 1835 400 val peyzash mts
2 0 Ivan Shishkin lviv 9546 1839 700 forest peyzach kyivstar
3 0 Vasil Petrov Lviv 9546 1850 590 Dostoievskiportret portret kyivstar 2 6
4 0 Karl Brylov Lviv 9546 1729 380 Pompej peyzash mts
5 0 Yurij Badger Lviv 9546 2008 120 voda peyzach Pepsi
6 0 Pavlo Guzenko Lviv 9546 2008 700 life modernizm Coca_cola 2 9
7 1 Cvitlana Berdnuk Lviv 9546 2008 200 molnia pryzach Kyivstar
8 1 Anna Vasilivna Lviv 9546 2008 190 nich peyzach life
9 0 Pavel Kocherzhenko Lviv 9546 2004 200 vazu peyrach Obolon 2 12
10 1 Anzhela Melnikova Lviv 9546 2007 600 Liliy peyzach mts
11 1 Tatyna Melnikova lviv 9546 2008 654 Surene peyzach kyivstar
12 0 Dmutro sevrykov lviv 9546 2003 567 kvitu peyzach mts 2 15
13 0 sergey sinelnikov lviv 9546 2006 300 pereprava istoruchnujpepsi pepsi
14 1 tatyna chebrava lviv 9546 2007 398 meteluk peyzach kyivstar
15 0 dmitriy sevryukov lviv 9546 205 470 lis peyzach life 2 18
16 0 sergiy sokursriy lviv 9546 2008 400 zima peyzach life
17 0 ivan shishkin lviv 9546 1850 960 vasuliy portret fanta
18 0 vasil petrov lviv 9546 1850 500 cnopka peyzach sprait 2 21
19 0 karl brylov lviv 9546 1729 800 nich modernizm life
20 0 yuriy badger lviv 9546 2008 100 conche peyzach life
21 1 clitlana berdnuk lviv 9546 2005 250 zemla peyzach kyivstar 2 24
22 0 pavlo guzenko lviv 9546 2008 300 derivo modernizm mts
23 1 anna vasilivna lviv 9546 2004 500 zachid peyzach obolon
24 0 dmutro serykov lviv 9546 2008 250 zori peyrach life 2 27
25 0 sergey sinelnikov lviv 9546 2008 480 port peyzach beeline
26 1 tatyna chebrava lviv 9546 2009 200 kylybaba peyzach beeline
27 1 palvo horetdy lviv 9546 2005 490 locha peyzach mts 2 31
29 0 pavlo sikov lviv 9546 2003 300 desna peyzach beeline
30 0 dmutro sevrukov lviv 9546 2008 490 sosna peyzach beeline
31 0 Yuriy Badger lviv 9546 205 300 nafta pryzach kyivstar
Стан бази даних після модифікації №5 додавання запису № 32 та видаляння запису № 17:
2 3
1 0 Ivan Ayvazovski Lviv 9546 1835 400 val peyzash mts
2 0 Ivan Shishkin lviv 9546 1839 700 forest peyzach kyivstar
3 0 Vasil Petrov Lviv 9546 1850 590 Dostoievskiportret portret kyivstar 2 6
4 0 Karl Brylov Lviv 9546 1729 380 Pompej peyzash mts
5 1 oksana kykech lviv 9546 1999 700 vola modernizm life
6 0 Pavlo Guzenko Lviv 9546 2008 700 life modernizm Coca_cola 2 9
7 1 Cvitlana Berdnuk Lviv 9546 2008 200 molnia pryzach Kyivstar
8 1 Anna Vasilivna Lviv 9546 2008 190 nich peyzach life
9 0 Pavel Kocherzhenko Lviv 9546 2004 200 vazu peyrach Obolon 2 12
10 1 Anzhela Melnikova Lviv 9546 2007 600 Liliy peyzach mts
11 1 Tatyna Melnikova lviv 9546 2008 654 Surene peyzach kyivstar
12 0 Dmutro sevrykov lviv 9546 2003 567 kvitu peyzach mts 2 15
13 0 sergey sinelnikov lviv 9546 2006 300 pereprava istoruchnujpepsi pepsi
14 1 tatyna chebrava lviv 9546 2007 398 meteluk peyzach kyivstar
15 0 dmitriy sevryukov lviv 9546 205 470 lis peyzach life 2 18
16 0 sergiy sokursriy lviv 9546 2008 400 zima peyzach life
18 0 vasil petrov lviv 9546 1850 500 cnopka peyzach sprait 2 21
19 0 karl brylov lviv 9546 1729 800 nich modernizm life
20 0 yuriy badger lviv 9546 2008 100 conche peyzach life
21 1 clitlana berdnuk lviv 9546 2005 250 zemla peyzach kyivstar ...