In un altro articolo abbiamo già parlato dei file sequenziali nel formato CSV (link articolo). Con questo articolo vediamo com’è possibile manipolare in C++ i file di questo formato. Supponiamo di avere il file anagrafica.csv della fig. [1] seguente, ottenuto dall’esportazione nel formato CSV della tabella del foglio di lavoro di Excel della fig. [2], seguendo il procedimento descritto nell’articolo precedente.
Esempio 1
Con questo semplice esempio vogliamo estrarre i record del file anagrafica.csv e visualizzarli a video nel modo seguente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
RECORD n. 1 Bianchi Andrea Viale Marconi, 40 56100 Pisa RECORD n. 2 Rossi Mario Via Mazzini, 12 85100 Potenza ecc... |
Nel file anagrafica.csv ciascuna riga rappresenta un record e in essa ciascun campo termina con un punto e virgola. Per estrarre i record, quindi, si può procedere con una lettura sequenziale di una riga per volta, utilizzando la funzione getline(), fino ad arrivare alla fine del file. In ciascuna riga letta, per estrarre i campi si può procedere con l’estrazione sequenziale delle sottostringhe chiuse dal carattere separatore ‘;’, fino ad arrivare alla fine della riga. Ciò può essere ottenuto in C++ nel modo seguente. Scelgo di lavorare con le stringhe in stile C++ e per l’estrazione delle sottostringhe dei campi sfrutto i metodi degli oggetti di classe string che abbiamo trattato in un altro articolo (link articolo).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
#include <iostream> #include <fstream> #include <string> using namespace std; void stampaRiga(string); int main(){ string s; fstream f_archivio("anagrafica.csv",ios::in); //apre il file CSV in LETTURA //lettura sequenziale del file CSV getline(f_archivio, s); //legge la prima riga del file CSV int i=1; //contatore per il n. di record letti while(!f_archivio.eof()){ cout<<"RECORD n. "<<i++<<endl; stampaRiga(s); getline(f_archivio, s); //legge la riga successiva del file CSV } f_archivio.close(); return 0; } //Estrae dalla stringa 'riga' i campi in maniera sequenziale e li visualizza a video void stampaRiga(string riga){ riga = riga + ";"; //aggiunge il carattere speciale di fine campo ';' anche all'ultimo campo while(riga.length()!=0){ //visualizza il primo campo della riga cout<<riga.substr(0, riga.find(";", 0))<<endl; //cancella nella riga il campo appena visualizzato (compreso il ;) riga.erase(0, riga.find(";", 0)+1); } cout<<endl; } |
In questo secondo esempio si vogliono estrarre i record del file anagrafica.csv e scriverli in un file di testo di nome tabella_clienti.txt in un formato tabellare più adatto per la visualizzazione e la stampa, come quello mostrato nella figura di sotto.
La logica di questo secondo programma è identica a quella del programma del primo esempio. Questa volta però i record estratti dal file anagrafica.txt non devono essere stampati a video ma scritti in un file, ossia lo stream dell’output non deve riguardare la periferica di output standard (il monitor), come nel primo esempio, ma un file di testo di nome tabella_clienti.txt.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
#include <iostream> #include <fstream> #include <string> #include <iomanip> //libreria delle funzioni di formattazione dell'output using namespace std; void stampaRigaSuFile(string , ofstream& ); int main(){ string s; ifstream f("anagrafica.csv"); //Apre il file CSV in LETTURA ofstream tabella("tabella_clienti.txt"); //Apre il file della tabella in OUTPUT //lettura sequenziale del file CSV getline(f, s); //legge la prima riga del file CSV while(!f.eof()){ stampaRigaSuFile(s, tabella); getline(f, s); //legge la riga successiva del file CSV } f.close(); tabella.close(); return 0; } //Estrae dalla stringa 'riga' i campi in maniera sequenziale, li formatta e li scrive nel file f_tabella void stampaRigaSuFile(string riga, ofstream& f_tabella ){ riga=riga + ";"; //aggiunge il carattere speciale di fine campo ';' anche all'ultimo campo while(riga.length()!=0){ //formatta lo stream dell'output sul file f_tabella<<setiosflags(ios::left)<<setw(20); //scrive su file il primo campo della stringa riga f_tabella<<riga.substr(0, riga.find(";",0)); //cancella nella stringa riga il primo campo appena visualizzato, compreso il ; riga.erase(0, riga.find(";",0)+1); } f_tabella<<endl; } |
- La prima per porre l’attenzione sulla sintassi di un parametro formale rappresentato da un oggetto associato ad uno stream su file: fstream& nomeFile. Si ricorda, infatti, che il nome di un oggetto è una variabile di tipo riferimento che, quindi, contiene l’indirizzo dell’oggetto a cui fa riferimento.
- La seconda per evidenziare che per formattare le righe in modo che i campi siano visualizzati perfettamente incolonnati nella tabella del file tabella_clienti.txt, sono state utilizzate due funzioni definite nel file di libreria iomanip:
- la funzione setiosflags() con la costante di manipolazione ios:left, per impostare l’allineamento a sinistra;
- la funzione setw(n) per impostare la larghezza di visualizzazione di ciascun campo espressa in numero di caratteri (n) .
Esempio 2-B
Il programma dell’esempio 2-A opera sul file in formato CSV estraendo ciascuna riga, che manipola separatamente per l’estrazione dei rispettivi campi. Quest’ultima cosa viene fatta dalla funzione stampRigaSulFile() che sfutta i metodi dell’oggetto stringa C++. L’approccio utilizzato in questa funzione è generale ed è indispensabile quando non si conosce a priori il numero di campi che compongono ciascuna riga.
Se invece il numero di campi delle righe è noto a priori, lo stesso problema può essere risolto operando in modo più semplice utilizzando la funzione getline() come mostrato di seguito:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
#include <iostream> #include <fstream> #include <string> #include <iomanip> //libreria delle funzioni di formattazione dell'output using namespace std; int main(){ string cognome, nome, indirizzo, cap, citta; ifstream f("anagrafica.csv"); //Apre il file CSV in LETTURA ofstream tabella("tabella_clienti.txt"); //Apre il file della tabella in OUTPUT //lettura sequenziale dei campi della prima riga del file CSV getline(f, cognome, ';'); getline(f, nome, ';'); getline(f, indirizzo, ';'); getline(f, cap, ';'); getline(f, citta); while(!f.eof()){ //formatta lo stream di output sul file della tabella e scrive i campi tabella<<setiosflags(ios::left)<<setw(20); tabella<<cognome; tabella<<setiosflags(ios::left)<<setw(20); tabella<<nome; tabella<<setiosflags(ios::left)<<setw(20); tabella<<indirizzo; tabella<<setiosflags(ios::left)<<setw(20); tabella<<cap; tabella<<citta<<endl; //lettura sequenziale dei campi della riga successiva getline(f, cognome, ';'); getline(f, nome, ';'); getline(f, indirizzo, ';'); getline(f, cap, ';'); getline(f, citta); } f.close(); tabella.close(); return 0; } |