PROGRAMMIAMO
C++ - File testo: Apertura/Chiusura
Apertura file

In C++, per poter utilizzare un file, bisogna per prima cosa assegnargli uno stream. Per creare uno stream e associarlo a un file occorre usare la seguente dichiarazione:

fstream nomestream(percorso, modo);

Più concretamente, supponiamo di voler aprire il file di nome "dati.txt" per poterlo leggere (modalità apertura). Il nome dello stream può essere scelto liberamente, come una normale variabile:

fstream fd("dati.txt", ios::in);

In realtà l'istruzione precedente comprende due operazioni distinte:

1) la dichiarazione di una variabile di nome fd e di tipo fstream
2) l'apertura di un file di nome "dati.txt" in modalità lettura e l'associazione dello stream fd al file

Più correttamente fstream è il nome di una classe e con la precedente istruzione noi stiamo dichiarando un oggetto di nome fd appartenente a quella classe e lo stiamo inizializzando utilizzando il costruttore della classe stessa. Per utilizzare la classe fstream bisogna aggiungere

#include <fstream>

all'inizio del proprio file C++.

Volendo sarebbe possibile eseguire le due operazioni con due istruzioni separate, così:

fstream fd;
fd.open("dati.txt", ios::in)

dove open è una member function della classe fstream che effettua le stesse operazioni del costruttore della classe (cioè, in pratica, inizializza le proprietà dell'oggetto che è stato precedentemente dichiarato).

Lo stream (nel nostro esempio fd, ma avremmo potuto scegliere liberamente qualunque altro nome) assomiglia un po' al bigliettino che ci viene dato all'ingresso di una discoteca o di un teatro quando consegniamo il nostro cappotto: ogni volta che vorremmo eseguire qualche operazione sul file dovremmo utilizzare lo stream associato al file. Lo stream è unico per un dato file e non può essere usato per più file contemporaneamente.

L'apertura di un file viene fatta sempre all'inizio, prima di leggere o scrivere su un file, e di norma una volta sola per ogni file.

Parleremo fra poco più approfonditamente del significato di quella misteriosa scritta ios::in che compare nella precedente dichiarazione di uno stream.

Percorso

Se il file si trova nella stessa cartella nella quale è contenuto il programma che lo utilizza, nell'istruzione di apertura è sufficiente indicare il nome del file, come negli esempi precedenti. Se invece il file si trova in un'altra cartella, occorre specificare il percorso (path) per giungere al file, cioè la successione di cartelle che contengono il file stesso.

Il percorso può essere assoluto o relativo. Nel primo caso si parte dalla cartella radice (root), ad es. C:, fino ad arrivare al file corrente, come in questo esempio:

fstream fd("c:/programmi/vc/temp/dati.txt", ios::in);

Si osservi l'uso dello slash / nel percorso invece del back slash \ comunemente usato nel sistema operativo windows. Lo slash / è vantaggioso sia perché è compatibile anche con altri sistemi operativi (es. Unix), sia perché il back slash viene utilizzato in C anche per i caratteri di escape (es. '\n') e quindi produrrebbe ambiguità. Volendo invece usare il back slash è necessario farlo precedere da un altro back slash (coè in pratica raddoppiarlo), allo scopo di specificare che si vuole indicare proprio il carattere '\' e non una sequenza di escape:

fstream fd("c:\\programmi\\vc\\temp\\dati.txt", ios::in);

Il percorso relativo fa invece riferimento alla cartella corrente, cioè a quella che contiene il programma che utilizza il file. Si usano a questo scopo i simboli . (per indicare la cartella corrente) e .. (per indicare la cartella immediatamente superiore - parent o genitrice - di quella corrente). Per esempio:

fstream fd("./prova/dati.txt", ios::in);

apre il file dati.txt che si trova nella sottocartella prova della cartella corrente.

fstream xx("../temp/num.txt", ios::in);

apre il file num.txt che si trova nella sottocartella temp della cartella genitrice, cioè della cartella che contiene la cartella corrente.

 

Modalità di apertura

Un file di testo può essere aperto in tre modalità, col seguente significato:

- lettura (ios::in): il file viene letto; se non esiste, non viene creato
- scrittura (ios::out): Il file viene scritto; se non esiste, viene creato vuoto; se già esiste l'operazione di scrittura è distruttiva (i vecchi dati vengono cancellati e sovrascritti)
- append (ios::out | ios::app): il file viene scritto; se non esiste, viene creato vuoto; se già esiste i dati vengono aggiunti in fondo al file, senza cancellare quelli preesistenti.

A seconda dei casi cambia la sintassi dell'operazione di apertura, nel seguente modo:

fstream fd("dati.txt", ios::in); // dati.txt aperto in lettura
fstream pt("valori.txt", ios::out); // valori.txt aperto in scrittura
fstream punt("num.txt", ios::out | ios::app); // num.txt aperto in append
fstream pfile("prova.dat", ios::in | ios::out);

Nell'ultimo esempio "prova.dat" è aperto sia in lettura che in scrittura, cioè è possibile leggere e scrivere sul file usando lo stesso stream (pfile nell'esempio). Si noti l'operatore or bit a bit '|' usato per concatenare due modalità di apertura.

La sintassi di apertura di un file in modalità append (ios::out | ios::app) è un po' complicata, perché bisogna specificare (contrariamente a quanto suggerisce il buon senso) che il file è stato aperto in scrittura (ios::out). Omettendo tale dichiarazione e scrivendo solo ios::app il file non viene modificato. La ragione di questo fatto è che fstream per default, in assenza di altre specificazioni, apre un file in modalità lettura (ios::in) e dunque non è possibile eseguire l'append su un file aperto in lettura.

Il C++ prevede due classi più specifiche, ifstream e ofstream, da utilizzare nel seguente modo:

ifstream fd("dati.txt"); // dati.txt aperto in lettura
ofstream pt("valori.txt"); // valori.txt aperto in scrittura
ofstream punt("num.txt", ios::app); // num.txt aperto in append

 

Chiusura file

L'operazione opposta all'apertura di un file è ovviamente la chiusura e la sua sintassi è molto semplice. Per esempio:

pt.close();

chiude il file il cui stream è pt. L'istruzione close libera lo stream associato al file, rendendolo nuovamente disponibile per altri file. Inoltre close salva il contenuto del file (nel caso di file aperti in scrittura), svuotando l'eventuale buffer di memoria.

Se non viene eseguita esplicitamente, la close viene comunque eseguita automaticamente al termine del programma. In ogni caso la close dev'essere usata solo alla fine, dopo che tutte le operazioni sul file sono state eseguite.

Clear

Quando si è verificata una condizione di errore (per esempio quando si tenta di aprire in lettura un file che non esiste) oppure quando si arriva a leggere l'ultimo dato contenuto in un file (end of file found) vengono settati automaticamente alcuni bit di stato, detti error state flags. Questi bit non vengono resettati automaticamente, neppure eseguendo una chiusura del file con la funzione close().

Ciò determina, in presenza di una condizione di errore, che successive operazioni compiute utilizzando uno stesso stream, anche dopo averlo chiuso, continuano a produrre risultati errati. Per esempio, cercando di riaprire uno stream dopo che è fallita un'apertura precedente, la nuova apertura continua a fallire, a causa del bit di stato che rimane settato su una segnalazione di errore.

Per evitare questi problemi, nel caso in cui si voglia riutilizzare uno stream per associarlo a diversi file, è buona norma dopo la chiusura dello stream effettuare un reset dei bit di errore con la funzione clear():

fstream fd;                        // dichiarazione dello stream

fd.open("dati.txt", ios::in); // dati.txt viene associato a fd e aperto in lettura

fd.close();                           // lo stream associato al file viene chiuso
fd.clear();                           // vengono resettati i flag di errore

fd.open("numero.txt", ios::in); // fd viene riutilizzato per aprire un altro file

 

 

precedente - successiva

Sito realizzato in base al template offerto da

http://www.graphixmania.it