You are on page 1of 16

Algoritmi şi programe de prelucrare a fişierelor

7. ALGORITMI DE PRELUCRARE A FIŞIERELOR


ORGANIZATE INDEXAT

Majoritatea aplicaţiilor de gestiune economică utilizează fişiere de date în care articolele


trebuie regăsite după valorile unui câmp de identificare, numit cheie. Problema corespondenţei între
chei şi numerele relative ale articolelor din fişierul de date se poate rezolva prin intermediul unui fişier
binar suplimentar, cu rol de tabelă de indexuri. O astfel de organizare se numeşte indexată. Articolele
fişierului tabelă de indexuri au structura din figura 7.1.

Indicator de Cheie Număr relativ (nr)


stare (is)

Fig. 7.1. Structura articolului din tabela de indexuri

Indicatorul de stare (is) are rol identic cu cel prezentat în capitolul referitor la fişierele
organizate relativ. Cheie este un câmp în care se memorează valoarea cheii articolului existent logic în
fişierul de date, al cărui număr relativ corespunzător este memorat în câmpul nr. Articolele tabelei de
indexuri sunt, în orice moment, sortate crescător după valorile câmpului cheie. Articolele din fişierul
de date sunt memorate aleator şi conţin câmpurile de date ale utilizatorului (pot conţine, redundant,
pentru o eventuală refacere după incidente, şi valorile cheii). O parte dintre acestea nu-şi regăsesc
corespondent în tabela de indexuri, fiind considerate şterse. Orice operaţie de acces la articolele
fişierului de date se realizează numai prin intermediul tabelei, gestionată automat de procedurile unui
unităţi specializate şi care este netransparentă utilizatorului.
Operaţiile de acces la nivel de fişier sunt: deschiderea şi închiderea fişierului de date. La rândul
ei, deschiderea poate fi: pentru creare (ca fişier nou) sau pentru consultare şi întreţinere (ca fişier
vechi). Procedurile realizează, pe lângă operaţiile asupra fişierului de date şi gestionarea automată a
tabelei de indexuri: formarea numelui său extern, asignarea numelui fizic la numele logic, deschiderea
ca fişier nou sau vechi, închiderea. Operaţiile de gestiune care se pot realiza cu fişierele de date astfel
organizate sunt:
• Crearea în acces secvenţial presupune furnizarea articolelor sortate strict crescător după
valorile câmpului ales drept cheie. Articolele sunt scrise cu ajutorul procedurii de scriere în acces
secvenţial. Eroarea de cheie invalidă poate apărea la tentativa de scriere a unui articol a cărui cheie este
mai mică sau egală decât ultima înscrisă în fişierul de date.
• Crearea în acces direct se realizează cu procedura de scriere în acces direct, articolele fiind
furnizate în orice ordine. Eroarea de cheie invalidă apare la tentativa de scriere a unui articol a cărui
cheie este egală cu una din cele prezente în fişier.
• Consultarea în acces secvenţial presupune regăsirea articolelor în ordinea strict crescătoare a
valorilor cheii. Ea se realizează cu ajutorul procedurii de citire în acces secvenţial, care detectează şi
sfârşitul fişierului de date.
• Consultarea în acces mixt permite selectarea unui grup de articole, memorate logic contiguu
în fişier, selecţie realizată pe baza valorilor cheii primului şi ultimului articol din grupul dorit. Accesul
mixt presupune poziţionarea pe primul articol prin citirea în acces direct (sau poziţionare şi citire în
acces secvenţial), urmată de exploatarea în acces secvenţial, până la găsirea cheii ultimului articol dorit,
sau până la sfârşitul fişierului.
• Adăugarea de articole se realizează utilizând procedura de scriere în acces direct. Articolele
pot fi furnizate în orice ordine a valorilor cheii. Eroarea de cheie invalidă apare la tentativa de scriere a
unui articol a cărui cheie este egală cu una deja existentă.
• Modificarea unor câmpuri din articol se realizează în următoarele etape:
- citirea articolului de modificat (în acces secvenţial sau direct);
- modificarea, în zona articol corespunzătoare, a câmpurilor dorite, cu excepţia câmpului cheie;
- rescrierea articolului, cu procedura de rescriere.
Algoritmi şi programe de prelucrare a fişierelor
Eroarea de cheie invalidă apare în cazul tentativei de rescriere a unui articol a cărui cheie este
diferită de cea a articolului citit anterior.
• Ştergerea în acces secvenţial elimină articolul curent din fişierul de date. în general, articolul
trebuie mai întâi identificat printr-o citire (în acces secvenţial sau direct) sau prin poziţionare.
Procedura returnează eroare în cazul tentativei de ştergere după ultimul articol existent.
• Ştergerea în acces direct elimină articolul a cărui cheie este precizată. Operaţia nu trebuie
precedată de citirea articolului şi returnează eroare în cazul furnizării unei chei inexistente în fişier. în
aplicaţii, este preferabilă ştergerea în acces secvenţial, deoarece permite (datorită citirii care o precede),
vizualizarea articolului şi luarea unei decizii în condiţii de siguranţă.
Unitatea Indexate cuprinde o serie de proceduri (primitive), cu rol de instrucţiuni de
intrare/ieşire la nivel de fişier şi articol, necesare realizării algoritmilor de prelucrare specifici
operaţiilor de gestiune a fişierelor, când se utilizează corespondenţa internă între valorile unui anumit
câmp din articole - numit cheie - şi numerele relative ale acestora. Tabela de corespondenţă între chei
şi numerele relative este memorată într-un fişier cu tip, a cărui gestiune este transferată integral
procedurilor aparţinând unităţii, astfel încât programele utilizatorului vor lucra exclusiv cu fişierul de
date. Totuşi, utilizatorul trebuie să ţină cont de existenţa tabelei de indexuri în vederea asigurării spa-
ţiului necesar pe disc şi manipulării concomitente a celor două fişiere (salvare, restaurare, ştergere etc.).
În unitate sunt făcute publice următoarele tipuri: TipFis, pentru tipul fişierului de date; TipArt,
pentru tipul articolului din fişierul de date; TipCheie, pentru tipul cheii.

Proceduri pentru realizarea operaţiilor de acces la nivel de fişier

♦ Procedura de deschidere a fişierului de date, pentru creare:

OpenNew(VAR f:TipFis; VAR nume:STRING; VAR ivk:BOOLEAN)

F este fişierul de date şi nume este identificatorul său extern. Ivk este indicator de eroare, care
returnează valoarea FALSE, dacă fişierul nu există sau valoarea TRUE, dacă fişierul există deja pe
disc. Procedura deschide, pentru creare, fişierul de date (ca fişier nou). Concomitent, se deschide şi
tabela de indexuri, al cărei nume extern este identic cu al fişierului de date, dar cu extensia .IDX.
Observaţie: la deschiderea tabelei de indexuri ca fişier nou, nu se verifică existenţa acestuia în
suport. Fişierul va fi şters şi recreat.

♦ Procedura de deschidere a fişierului de date, pentru consultare şi întreţinere:

OpenOld(VAR f:TipFis; VAR nume:STRING; VAR ivk:BOOLEAN)

F este fişierul de date şi nume este identificatorul său extern. Ivk este indicator de eroare, care
returnează valoarea FALSE, dacă ambele fişiere (de date şi de indexuri) există sau valoarea TRUE,
dacă unul din ele nu există. Procedura deschide, pentru consultare, ambele fişiere.

♦ Procedura pentru închiderea fişierului de date:

CloseFile(VAR f:TipFis)

F este fişierul de date. Procedura închide fişierul de date, precum şi tabela de indexuri.

Proceduri pentru realizarea operaţiilor de acces la nivel de articol

♦ Procedura pentru citirea în acces secvenţial a unui articol din fişierul de date:
Algoritmi şi programe de prelucrare a fişierelor
ReadSeqRec(VAR f:TipFis; VAR z:TipArt; VAR sf:BOOLEAN)

F este fişierul şi z este zona în care se citeşte articolul prezent în fişier. Sf este un indicator de
semnalare a atingerii sfârşitului fişierului de date şi are valorile: FALSE, dacă articolul s-a citit (şi nu
este sfârşit de fişier) sau TRUE, dacă s-a ajuns la sfârşit de fişier.
Procedura returnează articolul curent din fişierul de date (articolul următor ultimului accesat
printr-o operaţie de intrare/ieşire). Citirea unui articol din fişierul de date se realizează prin intermediul
tabelei de indexuri. în fapt, se citeşte un articol din tabelă, de la poziţia indicată de pointerul curent şi
apoi se citeşte articolul cu numărul relativ y.nr din fişierul de date (y este zona articol a tabelei de
indexuri).
Dacă pointerul indică marcatorul de sfârşit al tabelei, parametrul sf va returna valoarea TRUE.
Execuţia repetată a acestei proceduri are ca efect furnizarea articolelor din fişierul de date în ordinea
strict crescătoare a valorilor cheii.

♦ Procedura pentru citirea în acces direct a unui articol din fişierul de date:

ReadKeyRec(VAR f:TipFis; VAR z:TipArt; Key:TipCheie;


VAR ivk:BOOLEAN)

F este fişierul de date şi z este zona articol ataşată lui. Key precizează valoarea cheii articolului
care se citeşte. Ivk este indicator de eroare, care returnează valoarea FALSE, dacă articolul a fost
regăsit sau valoarea TRUE, dacă articolul este absent. Procedura caută, prin procedura Start, cheia cu
valoarea key şi dacă o găseşte, citeşte în z articolul cu numărul relativ y.nr şi face ivk=FALSE; dacă
nu o găseşte, face ivk:=TRUE.

♦ Procedura pentru scrierea în acces secvenţial a unui articol în fişierul de date:

WriteSeqRec(VAR f:TipFis; VAR z:TipArt; VAR ivk:BOOLEAN)

F este fişierul de date şi z este zona articol ataşată lui. Ivk este indicator de eroare, care
returnează valoarea FALSE, dacă articolul a fost scris, sau valoarea TRUE, în caz contrar. Procedura
adaugă un articol în fişierul de date, concomitent cu extinderea tabelei de indexuri cu o nouă
înregistrare, a cărei cheie este mai mare decât cele existente. În cazul în care cheia este mai mică sau
egală cu a ultimului articol din tabelă, se returnează eroare (ivk=TRUE) şi articolul nu se scrie.

♦ Procedura pentru scrierea în acces direct a unui articol în fişierul de date:

WriteKeyRec(VAR f:TipFis; VAR z:TipArt; Key:TipCheie;


VAR ivk:BOOLEAN)
F este fişierul de date şi z este zona articol ataşată lui. Key precizează valoarea cheii articolului
care se scrie. Ivk este indicator de eroare, care returnează valoarea FALSE, dacă articolul a fost scris
sau valoarea TRUE, în caz contrar.
Procedura adaugă un articol la sfârşitul fişierului de date. Cheia acestuia poate avea orice
valoare, inexistentă în tabela de indexuri. Iniţial, tabela se extinde cu un nou articol şi apoi se
reordonează (pentru a satisface cerinţele citirii secvenţiale). în cazul în care cheia furnizată de apelator
se regăseşte în tabelă, articolul nu se scrie şi se returnează eroare de cheie invalidă (ivk=TRUE).
Căutarea se face cu procedura Start.
Algoritmi şi programe de prelucrare a fişierelor
♦ Procedura pentru rescrierea unui articol în fişierul de date:

RewriteRec(VAR f:Tip VAR z:TipArt; VAR ivk:BOOLEAN)

F este fişierul de date şi z este zona articol ataşată lui. Ivk este indicator de eroare, care
returnează valoarea FALSE, dacă articolul a fost rescris sau valoarea TRUE, în caz contrar.
Procedura transferă datele din z în fişierul de date, în aceeaşi poziţie din care s-a citit anterior
(printr-o operaţie de citire în acces secvenţial sau direct). Tabela de indexuri nu se modifică. Procedura
verifică dacă valoarea cheii s-a modificat faţă de momentul citirii sale precedente, caz în care se
semnalează eroare de cheie invalidă (ivk=TRUE).

♦ Procedura pentru ştergerea în acces secvenţial a unui articol:

DeleteSeqRec(VAR f:TipFis; VAR ivk:BOOLEAN)

F este fişierul de date, iar ivk este indicator de eroare, care returnează valoarea FALSE, dacă
articolul a fost şters sau valoarea TRUE, în caz contrar.
Procedura şterge logic articolul curent din fişierul de date. ştergerea se realizează fizic în tabela
de indexuri. Iniţial se face y.is=0 şi apoi se elimină articolul din tabelă, prin procedura de sortare.
Eroarea de cheie invalidă (ivk=TRUE) este semnalată în cazul în care pointerul curent al tabelei de
indexuri indică marcatorul de sfârşit de fişier.

♦ Procedura pentru ştergerea în acces direct a unui articol :

DeleteKeyRec(VAR f:TipFis; Key:TipCheie; VAR ivk:BOOLEAN)

F este fişierul de date şi key precizează valoarea cheii articolului care se şterge. Ivk este
indicator de eroare, care returnează valoarea FALSE, dacă articolul a fost şters sau valoarea TRUE, în
caz contrar.
Procedura şterge logic din fişierul de date articolul a cărui cheie este furnizată ca parametru.
ştergerea se realizează fizic în tabela de indexuri, analog ştergerii în acces secvenţial. Eroarea de cheie
invalidă (ivk=TRUE) este semnalată în cazul în care articolul respectiv nu se regăseşte în tabelă.
Căutarea se face cu procedura Start.

♦ Procedura pentru poziţionare pe un anumit articol din fişierul de date:

Start(VAR f:TipFis; key:TipCheie; VAR ivk:BOOLEAN)

F este fişierul de date şi key precizează valoarea cheii articolului pe care se face poziţionarea.
Ivk este indicator de eroare, care returnează valoarea FALSE, dacă articolul există în fişier sau
valoarea TRUE, în caz contrar.
Procedura caută binar cheia cu valoarea key în tabela de indexuri şi dacă:
• o găseşte, face ivk=FALSE;
• nu o găseşte, face ivk:=TRUE.

Observaţie: Unitatea Indexate include o procedură de sortare (Sort) care nu este publică. Ea
sortează tabela de indexuri şi elimină articolul care are y.is=0.

unit indexate;
interface
type
tipcheie= word;
Algoritmi şi programe de prelucrare a fişierelor
tipart=record
nrm:tipcheie;
nume:string[25];
grupa:word;
nrd:1..20;
nota:array[1..20] of 0..10
end;
tipfis=file of tipart;
procedure opennew(var f:tipfis; var nume_fis:string; var ivk:boolean);
procedure openold(var f:tipfis; var nume_fis:string; var ivk:boolean);
procedure closefile(var f:tipfis);
procedure readseqrec(var f:tipfis; var z:tipart; var sf:boolean);
procedure readkeyrec(var f:tipfis; var z:tipart; key:tipcheie;
var ivk:boolean);
procedure writeseqrec(var f:tipfis; var z:tipart; var ivk:boolean);
procedure writekeyrec(var f:tipfis; var z:tipart; key:tipcheie;
var ivk:boolean);
procedure rewriterec(var f:tipfis; var z:tipart; var ivk:boolean);
procedure deleteseqrec(var f:tipfis; var ivk:boolean);
procedure deletekeyrec(var f:tipfis; key:tipcheie; var ivk:boolean);
procedure start(var f:tipfis; key:tipcheie; var ivk:boolean);
implementation
type
tipindex=record
is:0..1;
cheie:tipcheie;
nr:word
end;
tabela=file of tipindex;
var
g:tabela;
y:tipindex;

procedure sort(var g:tabela);


var
h:tabela; a,b:tipindex; i,j:word;
begin
assign(h,'temp.dat'); rewrite(h); seek(g,0);
for i:=1 to filesize(g) do
begin
read(g,a);
if a.is = 1 then write(h,a);
end;
close(g); seek(h,0);
for i:=1 to filesize(h)-1 do
begin
seek(h,i-1); read(h,a);
for j:=i+1 to filesize(h) do
begin
seek(h,j-1); read(h,b);
if a.cheie > b.cheie then
begin
Algoritmi şi programe de prelucrare a fişierelor
seek(h,i-1); write(h,b);
seek(h,j-1); write(h,a);
a:=b
end
end
end;
rewrite(g); seek(h,0);
for i:=1 to filesize(h) do
begin
read(h,a);
write(g,a)
end;
close(h); erase(h)
end;
{...........................................................................................................}
procedure opennew;
begin
assign(f,nume_fis); {$i-} reset(f) {$i+} ;
if ioresult <> 0 then
begin
ivk:=false; rewrite(f);
assign(g,copy(nume_fis,1,length(nume_fis)-4)+'.idx');
rewrite(g)
end
else ivk:=true
end;
{...........................................................................................................}

procedure openold;
begin
assign(f,nume_fis); {$i-} reset(f) {$i+} ;
if ioresult = 0 then
begin
ivk:=false;
assign(g,copy(nume_fis,1,length(nume_fis)-4)+'.idx');
{$i-} reset(g) {$i+};
if ioresult <> 0 then ivk:=true
end
else ivk:=true
end;
{...........................................................................................................}
procedure closefile;
begin
close(f); close(g)
end;
{...........................................................................................................}
procedure readseqrec;
begin
sf:=false;
{$i-} read(g,y) {$i+};
if ioresult <> 0 then sf:=true;
if not sf then
Algoritmi şi programe de prelucrare a fişierelor
begin
seek(g,filepos(g)-1);
read(g,y);
seek(f,y.nr);
read(f,z)
end
end;
{...........................................................................................................}
procedure readkeyrec;
begin
start(f,key,ivk);
if not ivk then
begin
seek(g,filepos(g)-1); read(g,y);
seek(f,y.nr); read(f,z)
end
end;
{...........................................................................................................}
procedure writeseqrec;
begin
ivk:=false;
if filepos(g) > 0 then
begin
seek(g,filesize(g)-1); read(g,y);
if y.cheie >= z.nrm then ivk:=true
end;
if not ivk then
begin
y.is:=1; y.cheie:=z.nrm; y.nr:=filesize(f);
write(g,y); seek(f,filesize(f)); write(f,z)
end
end;
{...........................................................................................................}
procedure writekeyrec;
begin
start(f,key,ivk);
if ivk then
begin
y.is:=1; y.cheie:=z.nrm; y.nr:=filesize(f);
seek(g,filesize(g)); write(g,y);
seek(f,filesize(f)); write(f,z);
sort(g); ivk:=false
end
else ivk:=true
end;
{...........................................................................................................}
procedure rewriterec;
begin
start(f,z.nrm,ivk);
if not ivk then
begin
seek(f,filepos(f)-1);
Algoritmi şi programe de prelucrare a fişierelor
write(f,z)
end
end;
{...........................................................................................................}
procedure deleteseqrec;
begin
if filepos(g) <= filesize(g) then
begin
ivk:=false; seek(g,filepos(g)-1);
y.is:=0; write(g,y); sort(g)
end
else ivk:=true
end;
{...........................................................................................................}
procedure deletekeyrec;
begin
start(f,key,ivk);
if not ivk then deleteseqrec(f,ivk)
end;
{...........................................................................................................}
procedure start;
var
i,ld,ls:word; vb:boolean;
begin
ivk:=false; vb:=false; ls:=1; ld:=filesize(g);
while not vb and (ld>=ls) do
begin
i:=(ls+ld) div 2;
seek(g,i-1); read(g,y);
if y.cheie = key then
vb:=true
else if y.cheie < key then
ls:=i+1
else
ld:=i-1;
end;
if not vb then
ivk:=true
end;
end.

Exerciţiul 1: Să se realizeze un program pentru crearea în acces direct a unui fişier indexat referitor
la situaţia şcolară a studenţilor unei facultăţi, cu articole având următoarea structură:

Număr Nume şi Grupa Număr Note obţinute:


matricol prenume discipline 1 2 … n
Word String[25] Word 1..20 0..10 0..10 0..10

Cheia este câmpul număr matricol. Datele se introduc de la tastatură, asigurându-se următoarele
validări:
- câmpul număr matricol: să fie numeric;

You might also like