МІНІСТЕРСТВО ОСВІТИ ТА НАУКИ УКРАЇНИ
Національний університет «Львівська політехніка»
Кафедра САПР
Звіт
Про виконання лабораторної роботи №2
З курсу:
«Бази даних»
Тема: ПРЯМИЙ МЕТОД ДОСТУПУ ДО ФАЙЛІВ НА ЗОВНІШНІХ ЗАПАМ’ЯТОВУЮЧИХ ПРИСТРОЯХ.
Мета: Розглянути органiзацiю i ведення файлiв прямого доступу; набути практичнi навички у програмуваннi алгоритмiв доступу хешуванням.
Текст програми:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#define recordSize (sizeof (animalRecord) + 2*9)
#define recordCount 10
#define blockSize (recordSize*recordCount)
#define blockCount 10
#define blockOver (blockSize*blockCount+60)
char mainPath[256] = "base.pdb";
char tempPath[] = "srchres.pdb";
char keyTab = 1;
FILE *dbFile = NULL, *tempFile = NULL;
class animalRecord
{
public:
int ID;
int Age;
char Pet[40+2];
char ownerName[40+2];
char Illness[40+2];
int Price;
char Notes[40+2];
float _current;
float _next;
int isSet;
int errorcode;
void Read(FILE *_current = NULL);
void Write(FILE *_current = NULL);
void GoUpToKey(FILE *_current = NULL);
animalRecord();
};
animalRecord::animalRecord()
{
ID = -1;
Age = 0;
_next=_current=-1;
strcpy (Pet,"NULL");
strcpy (ownerName,"NULL");
strcpy (Illness,"NULL");
Price = 0;
strcpy (Notes,"NULL");
errorcode = isSet = 0;
}
void animalRecord::Write(FILE* _current)
{
if (_current == NULL) return;
double cur = 0;
int i = 0;
cur = ftell(_current);
for (i=0;i<recordSize;i++)
fprintf(_current," ");
fseek(_current,cur,SEEK_SET);
fprintf(_current,"%c\n%d\n%d\n%s\n%s\n%s\n%d\n%s\n%06.0f\n%06.0f\n",keyTab,this->ID,this->Age,this->Pet,this->ownerName,this->Illness,this->Price,this->Notes,this->_current,this->_next);
}
void animalRecord::Read(FILE *_current)
{
animalRecord buf=animalRecord();
int eofflag=0, l, read=0;
char cbuf, key=0;
buf.isSet=0;
do
{
if(feof(_current)){eofflag=1;break;}
fscanf(_current,"%c",&key);
}while(key!=keyTab);
if(eofflag)
{
if(!read)
{
buf.errorcode=1;
*this = buf;
return;
}
}
//Считування з файлу--------------------------------------------------------------
fscanf(_current,"\n%d\n",&buf.ID);
fscanf(_current,"%d\n",&buf.Age);
for(l=0, fscanf(_current,"%c",&cbuf);cbuf!='\n';l++)
{
buf.Pet[l]=cbuf;
fscanf(_current,"%c",&cbuf);
}
buf.Pet[l]='\0';
for(l=0, fscanf(_current,"%c",&cbuf);cbuf!='\n';l++)
{
buf.ownerName[l]=cbuf;
fscanf(_current,"%c",&cbuf);
}
buf.ownerName[l]='\0';
for(l=0, fscanf(_current,"%c",&cbuf);cbuf!='\n';l++)
{
buf.Illness[l]=cbuf;
fscanf(_current,"%c",&cbuf);
}
buf.Illness[l]='\0';
fscanf(_current,"%d\n",&buf.Price);
for(l=0, fscanf(_current,"%c",&cbuf);cbuf!='\n';l++)
{
buf.Notes[l]=cbuf;
fscanf(_current,"%c",&cbuf);
}
buf.Notes[l]='\0';
fscanf(_current,"%f\n",&buf._current);
fscanf(_current,"%f\n",&buf._next);
buf.isSet=1;
*this = buf;
}
void animalRecord::GoUpToKey(FILE *_current)
{
int i=0,a;float ad;
char key;
if((ftell(_current))>0)
fseek(_current,-1,SEEK_CUR);
else{return;}
do
{
ad = ftell(_current);
fscanf(_current,"%c",&key);
fseek(_current,ad,SEEK_SET);
if(key=='\n')
a=-2;
else
a=-1;
fseek(_current,a,SEEK_CUR);
}while(key!=keyTab);
fseek(_current,1,SEEK_CUR);}
int reccmp(char str1[47], char str2[47], int count);
float GetBlockAddress (int);
void New();
void Open();
char* SetStr(int);
animalRecord Set (animalRecord set = animalRecord () );
void Insert (animalRecord sav = animalRecord () );
void Delete (animalRecord del = animalRecord () );
void Modify ();
void Find ();
void Print ();
int main()
{textmode(64);
clrscr();
do
{cout<<"Main menu:";
cout<<"\n\t1. Create new base"<<
"\n\t2. Open base"<<
"\n\t3. Insert"<<
"\n\t4. Delete"<<
"\n\t5. Modify"<<
"\n\t6. Find"<<
"\n\t7. Print"<<
"\n\t8. Quit program\n"<<
"Your choise: ";
switch(getch())
{case '1': clrscr();New(); break;
case '2': clrscr();Open(); break;
case '3': clrscr();Insert(); break;
case '4': clrscr();Delete(); break;
case '5': clrscr();Modify(); break;
case '6': clrscr();Find(); break;
case '7': clrscr();Print(); break;
case '8': clrscr();return 0;
default: clrscr();cout<<"Your choise is incorrect!\n";break;}
}while(1);}
void New()
{int R,B;
animalRecord buf = animalRecord();
cout<<"Enter path: ";
cin>>mainPath;
if((dbFile = fopen (mainPath, "w+"))== NULL) //Pomylka
{cout<<"Can't create base!\n";return;}
for (B=0;B<blockCount;B++)
{fseek(dbFile,GetBlockAddress(B),SEEK_SET);
for (R=0;R<recordCount*blockCount;R++)
{fseek(dbFile,R*recordSize,SEEK_SET);
buf._current=ftell(dbFile);
buf.Write(dbFile);}}
fseek(dbFile,blockOver-60,SEEK_SET);
fprintf(dbFile,"\n[OVERBLOCK #01:ADDRESS #%06d:]\n",blockOver);
fflush(dbFile);
cout<<"Base "<<mainPath<<" created...\n";}
void Open()
{cout<<"Enter path: ";
cin>>mainPath;
if((dbFile = fopen (mainPath, "r+"))== NULL) //Pomylka
{cout<<"Can't open base!\n";return;}
cout<<"Base "<<mainPath<<" opened...\n";}
animalRecord Set (animalRecord set)
{clrscr();
if (!set.isSet) set.ID=0;
do
{cout<<"Set the form:\n\n";
cout<<"1. ID: "<<set.ID<<"\n";
cout<<"2. Age: "<<set.Age<<"\n";
cout<<"3. Pet: "<<set.Pet<<"\n";
cout<<"4. Name: "<<set.ownerName<<"\n";
cout<<"5. Illness: "<<set.Illness<<"\n";
cout<<"6. Price: "<<set.Price<<"\n";
cout<<"7. Notes: "<<set.Notes<<"\n\n";
cout<<"8. Confirm\n";
cout<<"9. Cancel\n\n";
cout<<"Choise:\n";
switch (getch())
{case '1': cout<<"1. ID: ";cin>>set.ID;clrscr();break;
case '2': cout<<"2. Age: ";cin>>set.Age;clrscr();break;
case '3': cout<<"3. Pet: ";strcpy(set.Pet,SetStr(40));clrscr();break;
case '4': cout<<"4. Name: ";strcpy(set.ownerName,SetStr(40));clrscr();break;
case '5': cout<<"5. Illness: ";strcpy(set.Illness,SetStr(40));clrscr();break;
case '6': cout<<"6. Price: ";cin>>set.Price;clrscr();break;
case '7': cout<<"7. Notes: ";strcpy(set.Notes,SetStr(40));clrscr();break;
case '8': clrscr();set.isSet=1;return set;
case '9': clrscr();set.isSet=0;return set;
default: clrscr();cout<<"Your choise is incorrect!\n";}
}while(1);}
void Insert(animalRecord sav)
{FILE *dbFile = ::dbFile;
float BAD=0, tmp=0;
int i=0,j=0;
if (dbFile == NULL)
{cout<<"Base is not opened!\n";return;}
animalRecord ins = animalRecord();
if(sav.isSet)ins=sav;
else ins=Set();
animalRecord buf=animalRecord();
animalRecord buf1=animalRecord();
if(ins.isSet==0){return;}
BAD = GetBlockAddress (ins.ID);
rewind(dbFile);
fseek(dbFile,BAD,SEEK_SET);
for(i=0;i<recordCount;i++)
{fseek(dbFile,BAD+i*recordSize,SEEK_SET);
buf.Read(dbFile);
if (buf.ID!=-1)break;
}
if(i>=recordCount)
{fseek(dbFile,blockOver,SEEK_SET);
buf.Read(dbFile);
if(buf.errorcode!=1)
for(i=0;GetBlockAddress(buf.ID)!=BAD;i++)
{fseek(dbFile,buf._current+recordSize,SEEK_SET);
buf.Read(dbFile);
if ((buf.ID!=-1))
{if(buf.isSet==0){fseek(dbFile,BAD,SEEK_SET);buf.Read(dbFile);}
break;}
}
}
do
{
if ((buf.ID == ins.ID)&&(buf.isSet==1)){{return;}}
if (buf._next!=-1)fseek(dbFile,buf._next,SEEK_SET);
buf.Read(dbFile);
if ((buf.ID == ins.ID)&&(buf.isSet==1)){{return;}}
}
while(buf._next!=-1);
ins._current=BAD;
rewind(dbFile);
//begin of block
fseek (dbFile, BAD, SEEK_SET);
buf1.Read(dbFile);
buf = buf1;
for (i=0; (i<recordCount)&&(buf.ID!=-1); i++)
{fseek (dbFile, buf._current+recordSize, SEEK_SET);
buf.Read(dbFile);
if((i<recordCount)&&(buf.ID!=-1))buf1 = buf;
}
j=i;
if(i==0)
{for (i=0; (i<recordCount)&&(buf.ID==-1); i++)
{fseek (dbFile, BAD+i*recordSize, SEEK_SET);
buf.Read(dbFile);}
//Overblock
if(i>=recordCount)
{fseek(dbFile,blockOver,SEEK_SET);
buf.Read(dbFile);
for (i=0;(buf.isSet!=0);i++)
{if (GetBlockAddress(buf.ID) == BAD)
break;
fseek(dbFile,buf._current+recordSize,SEEK_SET);
buf.Read(dbFile);}
}
if(buf.isSet)
buf1._next=buf._current;
}
i=j;
if(i<recordCount)
{ins._current=(BAD+i*recordSize);
ins._next=buf1._next;
buf1._next=ins._current;
fseek(dbFile,buf1._current,SEEK_SET);
buf1.Write(dbFile);
fseek(dbFile,ins._current,SEEK_SET);
ins.Write(dbFile);}
//Overblock
else
{fseek(dbFile,blockOver,SEEK_SET);
buf.Read(dbFile);
for (i=0;(buf.ID!=-1)&&(buf.isSet!=0);i++)
{if (GetBlockAddress(buf.ID) == BAD)
buf1=buf;
fseek(dbFile,buf._current+recordSize,SEEK_SET);
buf.Read(dbFile);
}
ins._current=(blockOver+i*recordSize);
ins._next=(buf1._next);
buf1._next=(ins._current);
fseek(dbFile,buf1._current,SEEK_SET);
buf1.Write(dbFile);
fseek(dbFile,ins._current,SEEK_SET);
ins.Write(dbFile);
}
fflush(dbFile);
printf("animalRecord %d was inserted.\n\rCurrent Address: %06.0f. Next Address: %06.0f\n",ins.ID,ins._current,((ins._next<0)?0:ins._next));
}
void Delete(animalRecord del)
{FILE *dbFile = ::dbFile;
int ID = del.ID;
if (dbFile == NULL)
{cout<<"Base is not opened!\n";return;}
if (!del.isSet)
{del.ID=0;
while(1)
{cout<<"1. Delete Record (ID): "<<del.ID<<"\n";
cout<<"2. Delete\n";
cout<<"3. Cancel\n\nChoise:\n";
switch(getch())
{case '1': cout<<"1. Delete animalRecord (ID): ";cin>>del.ID;clrscr();break;
case '2': clrscr();goto ex1;
case '3': clrscr();return;
default: clrscr();cout<<"Your choise is incorrect\n";break;}
}}
ex1:;
ID=del.ID;
float BAD=0; int exist=0; int i;
animalRecord buf = animalRecord(),
buf1 = animalRecord();
BAD = GetBlockAddress(ID);
rewind(dbFile);
fseek(dbFile,BAD,SEEK_SET);
buf._current=(BAD);
buf1._current=(BAD);
buf.Read(dbFile);
for (i=0;(i<recordCount)&&(buf.isSet)&&(-1==buf.ID); i++)
{fseek(dbFile,BAD+i*recordSize,SEEK_SET);
buf.Read(dbFile);
}
if (!buf.isSet)
{return;}
if((-1==buf.ID))
{fseek(dbFile,blockOver,SEEK_SET);
buf.Read(dbFile);
for (i=0;(buf.isSet)&&(ID!=buf.ID);)
{fseek(dbFile,buf._current+recordSize,SEEK_SET);
buf.Read(dbFile);}
if (!buf.isSet)
{return;}
}
buf1 = buf;
exist=0;
do {
if ((buf.ID == ID)&&(buf.isSet==1))
{exist=1;
break;}
if (!buf.isSet)
{return;}
if(buf._next!=-1)
{fseek(dbFile,buf._current,SEEK_SET);
buf1.Read(dbFile);
fseek(dbFile,buf._next,SEEK_SET);
buf.Read(dbFile);}
else
if(!exist)
{return;}
}while((buf._next!=-1)&&(!exist));
buf1._next=(buf._next);
fseek(dbFile,buf1._current,SEEK_SET);
buf1.Write(dbFile);
fseek(dbFile,buf._current,SEEK_SET);
buf = animalRecord();
buf.ID=-1;
buf._current=(ftell(dbFile));
buf.Write(dbFile);
fflush(dbFile);
printf("Record %d was deleted.\n",ID);
}
void Modify()
{FILE *dbFile = ::dbFile;
int ID=0;
if (dbFile == NULL)
{cout<<"Base is not opened!\n";return;}//Pomylka
animalRecord mod = animalRecord();
mod.ID=0;
while(1)
{cout<<"1. Modify animalRecord (ID): "<<mod.ID<<"\n";
cout<<"2. Modify\n";
cout<<"3. Cancel\n\nChoise:\n";
switch(getch())
{case '1': cout<<"1. Modify animalRecord (ID): ";cin>>mod.ID;clrscr();break;
case '2': clrscr();goto ex2;
case '3': clrscr();return;
default: clrscr();cout<<"Your choise is incorrect\n";break;}
}
ex2:;
ID = mod.ID;
rewind(dbFile);
float BAD=0; int exist=0; int i;
animalRecord buf = animalRecord(),
buf1 = animalRecord();
BAD = GetBlockAddress(ID);
rewind(dbFile);
fseek(dbFile,BAD,SEEK_SET);
buf._current=(BAD);
buf1._current=(BAD);
buf.Read(dbFile);
for (i=0;(i<recordCount)&&(buf.isSet)&&(-1==buf.ID); i++)
{fseek(dbFile,BAD+i*recordSize,SEEK_SET);
buf.Read(dbFile);
}
if (!buf.isSet)
{return;}
if((-1==buf.ID))
{fseek(dbFile,blockOver,SEEK_SET);
buf.Read(dbFile);
for (i=0;(buf.isSet)&&(ID!=buf.ID);)
{fseek(dbFile,buf._current+recordSize,SEEK_SET);
buf.Read(dbFile);}
if (!buf.isSet)
{return;}}
while((buf._next!=-1)&&(buf.ID!=ID))
{fseek(dbFile,buf._next, SEEK_SET);
buf.Read(dbFile);
if (buf.isSet==0)
{return;}
}
if((buf._next==-1)&&(buf.ID!=ID))
{return;}
buf = Set(buf);
if(!buf.isSet)
{return;}
Delete(buf);
clrscr();
Insert (buf);clrscr();
printf("animalRecord %d was changed.\n\rCurrent Address: %06.0f. Next Address: %06.0f\n",buf.ID,buf._current,((buf._next<0)?0:buf._next));
}
void Find()
{int fnd=0;
clrscr();
if (dbFile == NULL)
{cout<<"Base is not opened!\n";return;}//Pomylka
int tofin=0;char k;
animalRecord set = animalRecord(),buf = animalRecord();
animalRecord tmp;
tempFile = fopen (tempPath,"w+");
cout<<"Search to:\n\n";
cout<<"1. ID "<<"\n";
cout<<"2. Age "<<"\n";
cout<<"3. Pet "<<"\n";
cout<<"4. Name "<<"\n";
cout<<"5. Illness "<<"\n";
cout<<"6. Price "<<"\n";
cout<<"7. Notes "<<"\n\n";
cout<<"8. Cancel\n\n";
cout<<"Choise:\n";
k = getch();
switch (k)
{case '1': cout<<"1. ID: ";cin>>set.ID;clrscr();break;
case '2': cout<<"2. Age: ";cin>>set.Age;clrscr();break;
case '3': cout<<"3. Pet: ";strcpy(set.Pet,SetStr(40));clrscr();break;
case '4': cout<<"4. Name: ";strcpy(set.ownerName,SetStr(10));clrscr();break;
case '5': cout<<"5. Illness: ";strcpy(set.Illness,SetStr(10));clrscr();break;
case '6': cout<<"6. Price: ";cin>>set.Price;clrscr();break;
case '7': cout<<"7. Notes : ";strcpy(set.Notes,SetStr(40));clrscr();break;
case '8': clrscr();return;
default: clrscr();cout<<"Your choise is incorrect!\n";return;}
tmp = set;
tofin = k - '1';
rewind(dbFile);
do{buf.Read(dbFile);
if(buf.isSet)
switch(tofin)
{ case 0: if(tmp.ID==buf.ID)
{fnd++;
buf.Write(tempFile);}break;
case 1: if(tmp.Age==buf.Age)
{fnd++;
buf.Write(tempFile);}break;
case 2: if(!(reccmp(tmp.Pet,buf.Pet,strlen(tmp.Pet))))
{fnd++;
buf.Write(tempFile);}break;
case 3: if(!(reccmp(tmp.ownerName,buf.ownerName,strlen(tmp.ownerName))))
{fnd++;
buf.Write(tempFile);}break;
case 4: if(!(reccmp(tmp.Illness,buf.Illness,strlen(tmp.Illness))))
{fnd++;
buf.Write(tempFile);}break;
case 5: if(tmp.Price==buf.Price)
{fnd++;
buf.Write(tempFile);}break;
case 6: if(!(reccmp(tmp.Notes,buf.Notes,strlen(tmp.Notes))))
{fnd++;
buf.Write(tempFile);}break;
}fflush(tempFile);
}while(buf.errorcode!=1);
clrscr();
cout<<"Results "<<fnd<<":\n";
rewind(tempFile);
do
{set.Read(tempFile);
if(set.ID!=-1){
cout<<"ID: "<<set.ID<<"\n";
cout<<"Age: "<<set.Age<<"\n";
cout<<"Pet: "<<set.Pet<<"\n";
cout<<"ownerName: "<<set.ownerName<<"\n";
cout<<"Illness: "<<set.Illness<<"\n";
cout<<"Price: "<<set.Price<<"\n";
cout<<"Notes: "<<set.Notes<<"\n\n";}
}while(set.errorcode!=1);
cout<<"Press enter...";while(getch()!=13);clrscr();}
void Print()
{animalRecord set;
if (dbFile == NULL)
{cout<<"Base is not opened!\n";return;}//Pomylka
rewind(dbFile);
do
{set.Read(dbFile);
if(set.ID!=-1){
cout<<"ID: "<<set.ID<<"\n";
cout<<"Age: "<<set.Age<<"\n";
cout<<"Pet: "<<set.Pet<<"\n";
cout<<"ownerName: "<<set.ownerName<<"\n";
cout<<"Illness: "<<set.Illness<<"\n";
cout<<"Price: "<<set.Price<<"\n";
cout<<"Notes: "<<set.Notes<<"\n\n";}
}while(set.errorcode!=1);
cout<<"Press enter...";while(getch()!=13);clrscr();
}
float GetBlockAddress (int ID)
{return (fmod(ID,blockCount) * blockSize);}
char* SetStr(int count)
{char k;
int curpos=0;
char* str = (char*) malloc (count*sizeof(char));
do
{k=getche();
switch (k)
{case 8: cprintf(" %c",8);curpos--;if(curpos<0)curpos=0;str[curpos]='\0';break;//backspace
case 13: if(curpos==0){str[curpos]='-';curpos++;}str[curpos]='\0';break;
case 27: strcpy(str,"-");k=13;break;
default: str[curpos]=k; curpos++;}
if(curpos>=count-2)
{k=13;str[curpos]=k; curpos++;}
}while(k!=13);
return str;}
int reccmp(char str1[47], char str2[47], int count)
{int i=0,l1=strlen(str1),l2=strlen(str2), res=