Informatica ARCHIVI E FILE: cancellazione di un record Prof. Ciaschetti La cancellazione di un record dall’archivio può essere di due tipi, logica o fisica. - Nella cancellazione logica, il record rimane fisicamente nel file, ma il suo contenuto informativo non ha più alcun valore per l’archivio. Nella cancellazione fisica, il record viene materialmente eliminato dall’archivio. La cancellazione logica è molto veloce, soprattutto se è possibile accedere direttamente al record da cancellare: si tratta, in buona sostanza, di effettuare una modifica di un apposito campo chiamato cancellato, che indica se il record è stato cancellato oppure no (come un flag). La cancellazione fisica invece è molto dispendiosa, e prevede la riscrittura di quasi l’intero archivio (tutto l’archivio tranne il record da cancellare). La soluzione più comunemente adottata prevede una combinazione di cancellazioni logiche e fisiche come segue: quando si vuole cancellare un record si effettua una cancellazione logica. Solo periodicamente si procederà a una compattazione del file, cancellando fisicamente tutti i record che sono stati cancellati logicamente, cioè scandendo tutto il file e riscrivendo solo i record non cancellati logicamente. Di seguito, è riportato il codice per effettuare la cancellazione logica utilizzando un campo apposito. Prese come esempio le seguenti strutture dati e variabili, struct cane { char nome[20]; char razza[20]; int eta; int cancellato; }; typedef struct cane dog; dog d; FILE *fp; Possiamo effettuare una cancellazione logica andando a modificare il campo cancellato, cioè alzando il flag. Nel codice che segue, supponiamo di non conoscere a priori la posizione del record da cancellare, e di dover effettuare quindi una ricerca del record. char nome_da_cancellare[20]; printf(“quale cane vuoi cancellare? ”); scanf(“%s”, nome_da_cancellare); fp = fopen("canile.dat", "r+"); int trovato = 0; while ((!trovato) && (!feof(fp))) /* cerca il record da cancellare */ { fread(&d, sizeof(dog), 1, fp); if (!strcmp(d.nome, nome_da_cancellare)) { trovato = 1; d.cancellato = 1; /* alza il flag */ fseek(fp, -sizeof(dog), SEEK_CUR); /* riscrivi il record */ fwrite(&d, sizeof(dog), 1, fp); } } fclose(fp); E’ importante, al momento dell’inserimento di un nuovo record nell’archivio, ricordarsi di inizializzare il campo cancellato a 0 per indicare che il record non è (logicamente) cancellato, e considerare tale campo nelle ricerche: se un record è stato cancellato, anche se solo logicamente, non dovrebbe essere più considerato. Come dicevamo, quando si effettua la cancellazione logica in questo modo, occorre prevedere una procedura di compattazione del file, che provveda a cancellare fisicamente i record che erano stati cancellati logicamente. Questa procedura non verrà fatta partire ogni volta che si vuole cancellare un record, ma solo ogni tanto, magari come processo da eseguire in background, quando il sistema non è impegnato in altre operazioni. La procedura prevede di riscrivere su un secondo file tutti i record tranne quelli cancellati logicamente, quindi eliminare il vecchio file e rinominare il nuovo con il vecchio nome. /* cancellazione fisica */ FILE *fp1, *fp2; fp1 = fopen("canile.dat", "r"); /* archivio vecchio */ fp2 = fopen("canile2.dat", "w"); /* archivio nuovo */ while(!feof(fp1)) { fread(&d, sizeof(dog), 1, fp); /* riscrivi sul nuovo archivio i record non cancellati logicamente */ if (!d.cancellato) fwrite(&d, sizeof(dog), 1, fp2); } fclose(fp1); fclose(fp2); remove("canile.dat"); /* rimuovi il vecchio archivio */ rename("canile2.dat","canile.dat"); /* rinomina il nuovo archivio come il vecchio */ NOTA: per includere la cancellazione nel progetto dell’archivio, aggiungere due funzioni 1) Cancella (effettua la cancellazione logica) 2) Compatta archivio (effettua la cancellazione fisica)