istream
e ostream
, altre classi per la gestione specifica di stream su file e in memoria: sono, rispettivamente, le classi ofstream
e ostrstream
(e le corrispondenti per l'input). Entrambe derivano anche da ostream
(istream
), per cui tutte le funzioni membro per la scrittura/lettura fino ad ora presentate sono utilizzabili anche le nuove arrivate. Tralasceremo la presentazione di strstream
per due motivi: le modalità di utilizzo dovrebbero essere ovvie non appena letta la guida del proprio compilatore al proposito; rischiano di diventare obsolete tra non molto, a causa delle più sofisticate stringstream
, cui non accenneremo in quanto esse si basano sul tipo string
, la cui trattazione non è stata inserita in questo testo. Le intestazioni delle classi fstream
si trovano nell'omonimo file, così come quelle per le strstream
.
I costruttori della classi ifstream
e ofstream
sono i seguenti12.6:
ifstream::ifstream ()
ifstream::ifstream (char* nome, int modalita) ofstream::ofstream () ofstream::ofstream (char* nome, int modalita) |
I costruttori default creano un oggetto di tipo ifstream
o ofstream
senza che esso venga collegato ad alcun file, per cui prima di effettuare qualunque operazione è necessario chiamare la funzione membro (sia per ifstream
che per ofstream
):
void open (char* nome, int modalita)
|
Il significato degli argomenti è il medesimo nei costruttori e in open
, cioè: nome è una stringa rappresentante il nome del file da aprire; modalita specifica la modalità di apertura del file12.7:
ios::in
apre il file in lettura;ios::out
apre il file in scrittura;ios::app
apre il file in scrittura e posiziona il cursore alla fine di esso.A questo punto presentiamo tre semplici (utili) esempi riguardo l'utilizzo dei file tramite la IOStream12.8.
Il primo esempio è un programmino per effettuare la copia di un file su di un altro; esso presuppone che l'utente inserisca da riga di comando il nome del file sorgente come primo argomento e quello di destinazione come secondo e ultimo argomento; nel caso il secondo argomento non venga specificato, l'uscita viene indirizzata sullo standard output. La copia avviene carattere per carattere, tramite le funzioni get()
e put()
.
// ex12_6_8.cpp // copia un file in un altro #include <iostream.h> #include <fstream.h> int main (int argc, char** argv) { // vogliamo che l'utente immetta almeno un argomento if (argc < 2) { cout << "ATTENZIONE\n" "\tdevi specificare almeno il file\n" "\tsorgente come argomento" << endl; return 1; } // ricordiamo che argv[0] e` il nome // dell'eseguibile avviato ifstream in (argv[1], ios::in); if (!in) { cout << "ATTENZIONE\n" "\tci sono problemi in fase di apertura\n" "\tdel file sorgente che hai specificato\n" "\t(probabilmente sorgente non esiste)" << endl; return 1; } // effettuiamo la copia per carattere char c; // se non e` stato specificato il secondo argomento // l'output avviene a video if (argc >= 3) { ofstream out (argv[2], ios::out); while (in.get(c)) out.put(c); } else while (in.get(c)) cout.put(c); return 0; }
L'esempio successivo apre un file in lettura, come primo argomento da riga di comando, e ne stampa il numero di parole (qualunque stringa separata da almeno uno spazio è considerata ``parola'') e di righe. Viene usato, rispettivamente, l'operatore `<<
' e la funzione membro getline()
.
// ex12_6_9.cpp #include <iostream.h> #include <fstream.h> const int MAX_LUNG_PAROLA = 200; const int MAX_LUNG_RIGA = 500; int main (int argc, char** argv) { if (argc < 2) { cout << "manca un argomento" << endl; return 1; } // inizializza variabili ifstream in (argv[1], ios::in); char pbuf[MAX_LUNG_PAROLA]; char rbuf[MAX_LUNG_RIGA]; // conta parole unsigned counter = 0; while (in >> pbuf) counter++; cout << "no. parole:\t" << counter << endl; // resetta variabili counter = 0; in.close(); in.open(argv[1], ios::in); // conta righe while (in.getline(rbuf, MAX_LUNG_RIGA)) counter++; cout << "no. righe:\t" << counter << endl; return 0; }
L'ultimo esempio consiste in un programmino che sostituisce in un file tutte le occorrenze di una stringa (se separata da spazi dalle altre stringhe) con un altra e salva il tutto in un secondo file; esso accetta da riga di comando tre argomenti: il nome del file da aprire, la stringa sostituenda, la stringa sostituente. Abbiamo utilizzato l'operatore `<<
' per effettuare un rozzo parsing sul file in entrata, il quale elimina gli spazi bianchi; siccome vogliamo che in uscita il nostro file modificato mantenga questi ultimi inalterati, abbiamo utilizzato un piccolo artificio, che tra l'altro ci permette di mostrare un semplice utilizzo della funzione peek()
.
// ex12_6_10.cpp // cerca all'interno di un file XXX una stringa // e la sostituisce con un altra // salvando il risultato nel file XXX.sub #include <iostream.h> #include <fstream.h> #include <string.h> const int MAX_LUNG_PAROLA = 500; int main (int argc, char** argv) { if (argc < 4) { cout << "mancano " << (4-argc) << " argomenti" << endl; return 1; } // apre il file argv[1] in lettura ifstream in(argv[1], ios::in); if (!in) { cout << "il file " << argv[1] << " non esiste" << endl; return 1; } const int n = strlen(argv[1]); char* nomeFileOut = new char[n + 5]; for (int i = 0; i < n; i++) nomeFileOut[i] = argv[1][i]; nomeFileOut[n] = '.'; nomeFileOut[n+1] = 's'; nomeFileOut[n+2] = 'u'; nomeFileOut[n+3] = 'b'; nomeFileOut[n+4] = '\0'; // apre il file nomeFileOut in scrittura ofstream out (nomeFileOut, ios::out); // effettua un rozzo parsing del file sorgente // cercando le occorrenze da sostituire int counter = 0; char buf[MAX_LUNG_PAROLA]; while (1) { if (!in) break; switch (in.peek()) { case '\n': out << '\n'; break; case ' ': out << ' '; break; } in >> buf; if (strcmp(buf, argv[2]) == 0) { out << argv[3]; counter++; } else out << buf; } cout << "modificate " << counter << " parole" << endl; return 0; }