Linguaggio C++ Un esempio: Registrazione e lettura di dati in un file File e Stream.
-
Upload
augusto-bellucci -
Category
Documents
-
view
239 -
download
5
Transcript of Linguaggio C++ Un esempio: Registrazione e lettura di dati in un file File e Stream.
Linguaggio C++
Un esempio:Registrazione e lettura di dati in un file
File e Stream
In molte situazioni le informazioni che un
programma deve elaborare possono provenire da
sorgenti diverse dalla comune tastiera.
Analogamente, i dati elaborati, anziché essere
visualizzati o stampati, possono essere memorizzati
e conservati in memorie di massa, generando così
una nuova sorgente di dati disponibile per altri
programmi
La registrazione dei dati sulle memorie di massa è
organizzata in modo ordinato e secondo uno standard
preciso: un insieme di dati così archiviato si definisce
file ed è identificato mediante un nome e,
opzionalmente, da un’estensione
Nome ed estensione sono separati da un punto. Lo
scopo dell’estensione è quello di individuare file
omogenei, ovvero che contengono la stessa tipologia
di informazioni (testo, documenti, immagini, brani
musicali, filmati,...). Esempi tipici sono txt, rtf, jpg,
mp3, avi…
I file si possono suddividere in due categorie: file di
testo e file binari.
I file di testo sono solitamente destinati a contenere
informazioni listabili, cioè visualizzabili e stampabili
direttamente oppure mediante un qualunque editor. Un
file sorgente C++ o un file prodotto con Blocco note di
Windows sono esempi tipici di file di testo
I file binari sono utilizzati per memorizzare qualsiasi
tipo d’informazione e possono contenere una
successione di byte qualsiasi, pertanto, non
necessariamente in un formato listabile. Un
programma eseguibile, un file mp3 o jpg sono tutti
esempi di file binari
Per accedere a un file occorre compiere delle semplici
operazioni logiche:
1) aprire il file: si indica al Sistema Operativo
su quale file operare;
2) leggere e/o scrivere i dati: si specificano
quali sono le informazioni da trasferire;
3) chiudere il file: si concludono le operazioni
sul file
In C++ lo scambio di informazioni tra un programma
e un qualunque file avviene attraverso un oggetto
astratto, lo stream. Uno stream («flusso») può essere
pensato come un «canale» tra la sorgente e la
destinazione, attraverso il quale fluiscono i dati
Questo livello di astrazione consente di semplificare
notevolmente le operazioni di input/output dei dati
poiché il programma interagisce solo con lo stream, e
non con una molteplicità di periferiche differenti. Al
programmatore occorre conoscere solo come
scambiare informazioni mediante gli stream
Anche l’input dei dati dalla tastiera e il loro output
sullo schermo avviene attraverso degli stream. Tra la
tastiera e il programma, i dati viaggiano attraverso uno
stream d’ingresso (cin) mentre tra il programma e lo
schermo sono incanalati in uno stream d’uscita
(cout)
Grazie a questo livello di astrazione, agli stream
associati ai file su disco è possibile applicare gli stessi
operatori usati con cin e cout, rispettivamente,
l’operatore di estrazione >> (input) e quello di
inserzione << (output)
Un esempio
Si desidera registrare i dati anagrafici degli iscritti
a una gara in un file, denominato iscritti.txt. Ogni
riga del file deve contenere il cognome del
partecipante seguito dalla sua altezza e dal peso.
In seguito, questo file deve poter essere letto per
visualizzare sullo schermo l’elenco dei partecipanti
Scrittura e lettura su un file
Per accedere alle informazioni contenute in un file su
disco è necessario innanzitutto connetterlo a un
apposito stream. Solo allora sarà possibile la
comunicazione tra file e programma. L’associazione
file-stream prende anche il nome di «apertura del
file»
Per esempio, la seguente riga di programma:
ofstream iscritti("iscritti.txt");
apre un file in scrittura ovvero crea un nuovo file su
disco, iscritti.txt, e lo connette allo stream
d’uscita iscritti, di tipo ofstream (output file
stream, definito nell’header file <fstream>)
Analogamente l’istruzione:
ifstream iscritti("iscritti.txt");
apre in lettura un file esistente, di nome
iscritti.txt, e lo connette allo stream d’ingresso
iscritti, di tipo ifstream (input file stream,
anch’esso definito nell’header file <fstream>)
Ovviamente, l’apertura di un file è significativa solo se
la connessione tra file e stream è possibile. Se, per
qualsiasi ragione, il file non è accessibile (disco pieno,
file inesistente o protetto dalla scrittura,…) non ha
nemmeno senso operare sul suo contenuto
Il successo dell’operazione di apertura può essere
verificato con un test sullo stato dello stream:
if( !iscritti )
cout << "Errore di apertura del file!";
Lo stato false di iscritti indica che la connessione
del file allo stream non è riuscita; viceversa lo stato
true ne segnala la regolarità
Nella modalità di apertura predefinita di un uno
stream di tipo ofstream, viene creato un nuovo file di
testo. Se lo stesso programma è impiegato per
aggiungere nuovi dati, si ottiene il risultato di
eliminare quelli precedenti. Per evitare questo
problema occorre modificare il comportamento di
default di ofstream mediante l’enumeratore
predefinito ios::app
// Apertura del file (connessione file-stream)
ofstream iscritti("iscritti.txt", ios::app);
Questo enumeratore fa sì che il file specificato sia
aperto per delle operazioni di scrittura e che i nuovi
dati siano aggiunti alla sua fine (append). Se il file non
esiste, viene creato
Per aprire un file binario occorre specificare
esplicitamente l’enumeratore predefinito
ios::binary. Per esempio, per aprire in scrittura e
come binario un file si può scrivere:
ofstream iscritti("iscritti.txt", ios::app |
ios::binary);
In questo caso l’operatore di bitwise OR | combina
gli effetti degli enumeratori predefiniti ios::app e
ios::binary
Per scrivere dei dati su un file il modo più semplice è
quello d’inviarli allo stream associato mediante
l’operatore di inserzione <<, come per lo stream
cout:
iscritti << cognome << '\t' << altezza
<< '\t' << peso << endl;
Con un’unica operazione, questa riga di programma
scrive i dati relativi al cognome, all’altezza e al peso
del partecipante nello stream iscritti
Prima di essere scritti sul file, l’operatore di
inserzione << converte i dati nei caratteri
corrispondenti, secondo le specifiche di formato
(width, fill, precision,...). In questi casi si parla di
output formattato
Nell’esempio ogni dato è distinto dal successivo da
una tabulazione, '\t'; se lo stream iscritti è
associato a un file di testo, questo «spazio bianco» sarà
internamente convertito in un’appropriata sequenza di
spazi. Il manipolatore endl invia allo stream un
ritorno a capo ('\n'), ma contemporaneamente causa
la scrittura immediata del contenuto dello stream sul
file
// Scrittura di dati su file
#include <iostream>#include <fstream>
using namespace std;
int main() { unsigned n; char cognome[20]; unsigned short altezza; // in cm unsigned short peso; // in Kg cout << "Numero di elementi (0 = fine): "; cin >> n;
Il programma che segue riepiloga i concetti fin qui esposti:
// Acquisizione dati if(n > 0) { // Apertura in scrittura del file di testo ofstream iscritti("iscritti.txt", ios::app); if(iscritti) { // Se non si sono verificati errori for(unsigned i = 0; i < n; i++) { // Acquisizione dati mediante lo stream cin cout << "\nCognome: "; cin >> cognome; cout << "Altezza: "; cin >> altezza; cout << "Peso...: "; cin >> peso; // Scrittura dei dati formattati nel file iscritti << cognome << '\t' << altezza << '\t' << peso << endl; } } else cout << "Errore di apertura file" << endl;}
}
Nella figura che segue è visibile un possibile output
sul file iscritti.txt. Questo file di testo può essere
visualizzato anche mediante un qualsiasi editor di
testo quale, ad esempio, Blocco note (Notepad) di
Microsoft Windows
Landini 175 70
Cerami 185 80
Ponzati 178 72
Candela 192 87
Renati 168 65
Le informazioni memorizzate nel file iscritti.txt
possono essere utilizzate come input di un altro
programma. Per farlo occorre associare il file ad uno
stream d’ingresso e leggerne il contenuto. Poiché in
questo caso i dati sono costituiti da caratteri e «spazi
bianchi», è possibile estrarli mediante l’operatore di
estrazione >>, come normalmente avviene con lo
stream cin
Per esempio, la seguente riga di programma:
«estrae» dal file associato allo stream iscritti i
caratteri che costituiscono ogni dato e li converte nel
tipo delle variabili corrispondenti. Gli «spazi bianchi»
che separano un dato dall’altro sono ignorati
iscritti >> cognome >> altezza >> peso;
Se l’acquisizione s’è svolta senza errori, lo stream
assume il valore true altrimenti, se si verificano dei
problemi di lettura o nella conversione dei dati o si
tenta di leggere oltre la fine del file, lo stato di stream
diventa false. In questo modo con un semplice test
dello stream è possibile verificare se i dati letti sono
corretti
Una volta raggiunta la fine del file, non ha ovviamente
più senso effettuare altre letture dallo stream. Questa
condizione si può verificare mediante il metodo
eof() (end of file) che assume il valore true dopo
che è stato letto l’ultimo carattere dello stream.
Il programma che segue riassume i concetti fin qui
esposti
// Lettura di dati da un file
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
char cognome[20];
unsigned short altezza; // in cm
unsigned short peso; // in Kg
// Apertura in lettura del file di testo
ifstream iscritti("iscritti.txt");
if(iscritti) { // Se non si sono verificati errori
do {
// Legge una riga del file e verifica lo stream
if( iscritti >> cognome >> altezza >> peso )
// Scrittura dei dati sullo schermo
cout << cognome << '\t' << altezza
<< '\t' << peso << endl;
else {
cout << "Errore di lettura" << endl;
break;
}
} while(!iscritti.eof()); // Ripete se non è finito
}
else
cout << "Non e' possibile aprire il file" << endl;
}
Quando non è più necessario accedere a un file, deve
essere chiuso, in modo da liberare risorse e rendere
nuovamente disponibile lo stream associato. I file
vengono automaticamente chiusi alla fine del
programma o quando lo stream termina il proprio
periodo di vita
La chiusura di un file elimina l’associazione con lo
stream e restituisce al Sistema Operativo le risorse che
utilizzava. Se per qualche ragione è necessario
chiudere un file prima della fine del programma è
possibile farlo mediante il metodo close():
iscritti.close();