User Tools

Site Tools


appunti3s:oggetti_di_tipo_stream
per tornare all'indice → Linguaggio C++

Stream (flusso di dati)

Si sono già utilizzati gli operatori “extractor” >> e “insertion” << nell pagine della programmazione imperativa

Nel seguente testo i termini input e output sono sempre riferiti al programma, quindi:
  • “in input” significa “in ingresso al programma”
  • “in output” significa “in uscita dal programma”

Operatore Extractor >>

Solo adesso, giunti a questo livello di studio, si può comprendere che Extractor è un operatore che si applica su due oggetti: un oggetto Istream (stream di input, come std::cin) che rappresenta cioè i caratteri in ingresso al programma (come quelli provenienti dalla tastiera) e un oggetto dove i caratteri sono destinati a finire (come le variabili del programma).

std::cin >> varstring;

Operatore Insertion <<

Anche questo è un operatore che si applica su due oggetti: un oggetto Ostream (stream di output, come std::cout) che rappresenta i caratteri in uscita dal programma (come quelli diretti verso il monitor) e un oggetto nella memoria, da cui i caratteri provengono (come le variabili del programma o le costanti).

std::cout << varstring << "testo";

Questi operatori restituiscono a loro volta un oggetto stream

 ostream& operator<< ( ostream&,...)

quindi possono essere usati ricorsivamente, o annidati, eseguendo l'espressione come se si fossero aggiunte le parentesi tonde.

 (std::cout << "Mario ") << "Rossi" << std::endl;

fstream

In modo analogo a std::cout e cin, il programmatore può definire nuovi oggetti stream di output (o di input) e successivamente applicare l'operatore Insertion <<(o Extractor >>) per eseguire operazioni di output (o di input) per il programma.

std::ifstream is;  //dichiarazione oggetto input stream (di input per il programma)
is >> varstring;   // operazione di lettura con Extractor: è input per il programma!
                   // l'input si arresta al primo spazio bianco....
std::ofstream os;  //dichiarazione oggetto output stream (di output per il programma)
os << "testo";     //operazione di scrittura con Insertion: è output per il programma!

Questi sono “oggetti” e devono essere utilizzati nell'ottica della programmazione orientata agli oggetti. Gli oggetti di tipo ifstream sono predefiniti per l'input, mentre ofstream sono predefiniti per l'output. Gli oggetti fstream possono essere usati indifferentemente per Input e Output.

File

Un file contiene una sequenza di numeri memorizzati permanentemente sulla memoria di massa, utilizzando una certa organizzazione interna dei dati.

  • Se ogni Byte rappresenta nella realtà un carattere (char), il file può essere trattato come un file di caratteri (metodo predefinito).
  • Se rappresenta altro (es: un float è un valore che occupa diversi Byte) il file deve essere trattato come un file binario.

Se non diversamente specificato un file è aperto come file di testo, altrimenti in caso di immagini, file audio, file eseguibili, si devono aprire in formato binario.

Un file possiede un nome (di solito con estensione) una data e il formato in cui sono organizzati i dati al suo interno. (vedere problema dei caratteri nei nomi dei file e problema dei formati.pdf proprietari) Un file può essere aperto in diversi “modi”: in lettura, in scrittura o in entrambi i modi.

stream.cpp
/* questo programma è stato scritto da Fabio
 * 
 * esempio di lettura e scrittura su file di testo
 */
#include <string>
#include <iostream>
#include <fstream>
 
int main()
{
   std::string nomeFile("nessuno.txt");
 
   std::cout << "Inserire il nome del file \n" ;
   std::cin >> nomeFile;
 
         // definisce un oggetto stream aperto in lettura e scrittura (deve esistere).
         // se era aperto solo in scrittura poteva anche non esistere         
   std::fstream flussoFile(nomeFile.c_str(),std::ios_base::in|std::ios_base::out);  
 
	// ma apertura in lettura puo' dare errore se file inesistente.
	if (!flussoFile) std::cout << "can't open input file"<<std::endl;
 
   std::string parola("bla");
   flussoFile << "testo a piacere...";  // operazione di scrittura con Insertion: è output dal programma!
   flussoFile >> parola;   // operazione di lettura con Extractor: è input per il programma! attenzione agli spazi bianchi...
 
   return 0;
}

Usando i file di testo, oltre a leggere una parola su una variabile (string) si può leggere anche un gruppo di cifre, che rappresentano un numero, su una variabile float (o di altro tipo numerico)

   double d;
   flussoFile >> d;  // extractor preleva caratteri dal file e li trasforma in dati dentro d
   flussoFile << d;  // insertion deposita caratteri dentro il file a partire dai dati dentro d

Stato del flusso file

Gli oggetti stream possiedono degli stati che possono essere verificati con delle funzioni:

flussoFile.good(); // restituisce true se è tutto ok
flussoFile.eof();  // restituisce true se la lettura del file ha raggiunto la fine del file.
flussoFile.fail(); // restituisce true se l'ultima operazione sul file è fallita.
flussoFile.bad();  // restituisce true se l'errore è più grave.
flussoFile.clear();  // pulisce lo stato per riprovare l'operazione
flussoFile.unget();  // restituisce indietro il dato letto
flussoFile.exceptions(ios_base::badbit);  // lancia un'eccezione

funzione open

#include <fstream>
61.cpp
#include <string>
#include <iostream>
#include <fstream>
 
int main()
{
  std::string parola = "ciao";
  const std::string nomeFile = "prova.txt"; // sarebbe errore passare una stringa costante,
                                            // bisogna passare una costante stringa...  
  std::fstream mioFile; 
 
  mioFile.open("prova.txt", std::ios_base::in|std::ios_base::out); //aperto in lettura e scrittura
  std::cout << "Salvo una parola" << std::endl;
  mioFile << parola << std::endl;
 
  mioFile.close(); // opzionale. chiudo il collegamento con il file "prova.txt"
                   // e posso riutilizzare l'oggetto per altri file...
 
  return 0;
}

Il buffer serve per non scrivere un carattere alla volta nel file, ma per riempire un vettore e scrivere solo quando il vettore è pieno, oppure quando lo decide il programmatore con flush()

Posizionamento

Un file può essere letto sequenzialmente, oppure ci si può spostare su e giù per il file (0.. n-1)

   std::ifstream flussoFile(nomeFile.c_str()); //apertura in lettura predefinita
   flussoFile.seekg(5);    // posizione 6 (Seek) per lettura (Get).
   flussoFile >> varchar;  // lettura di un carattere
   std::ofstream flussoFile(nomeFile.c_str()); //apertura in scrittura predefinita
   flussoFile.seekp(5);    // posizione 6 (Seek) per scrittura (Put).
   flussoFile << "z";  // scrittura di un carattere

Approfondimento

Provare a scrivere un programma che legge separatamente nome e cognome e poi mette questi dati all'interno di un'unica variabile usando l'operatore concatenazione (+).

Provare a scrivere l'esempio inverso… (aiutati da std::stringstream in <sstream>)

Provare a scrivere un programma che legge dati da un file in un buffer (aiutati da std::stringstream in <sstream>)

63.cpp
#include <iostream>
#include <sstream>
/* programma che usa un buffer per scrivere in un file */
 
int main() 
{   
   std::ofstream flussoFile(nomeFile.c_str()); //apertura in scrittura predefinita  
                                     // non si inviano direttamente dati al file (mem. massa)
                                     // ma si accumulano temporaneamente in uno stream (mem. centrale)
   std::ostringstream streambuffer;  // accumula temporaneamente dati
 
   streambuffer << "testo" << std::endl;
   streambuffer << "inserito a ripetizione" << std::endl;
 
   std::string varstring = streambuffer.str();   // trasforma il buffer in una string
                                                 // per poterla inviare ad un fstream
 
   flussoFile << varstring;           // effettiva scrittura nel file
 
   return 0;  
}
per tornare all'indice → Linguaggio C++
appunti3s/oggetti_di_tipo_stream.txt · Last modified: 2020/06/08 22:19 by 127.0.0.1