МІНІСТЕРСТВО ОСВІТИ ТА НАУКИ УКРАЇНИ
Національний університет «Львівська політехніка»
Кафедра САПР
Звіт
Про виконання лабораторної роботи №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=