SlideShare ist ein Scribd-Unternehmen logo
1 von 105
Downloaden Sie, um offline zu lesen
Lezione 14

Stream, fstream e
              file
Input streams 1/2
    stream: sequenza di caratteri


    istream:    meccanismo       per     convertire


    sequenze di caratteri in valori di diverso tipo
    standard istream: cin


        tipicamente associato al terminale da cui è
    

        fatto partire il programma
        appartiene al namespace std
    


            E' questo uno dei motivi per cui abbiamo
        

            aggiunto nei nostri programmi la
            direttiva
            using namespace std ;
                                                  2
Input streams 2/2
    Come si leggono valori?




    Operatore >>           (leggi, estrai)




    Input formattato ...





                                             3
Input formattato
    Le cifre sono convertite in numeri se si


    leggono interi o reali

    I caratteri speciali sono saltati se si


    leggono singoli caratteri
        Ad esempio è saltato il newline 'n'
    



    Gli spazi bianchi (spazio, tab, newline,


    form-feed, ...) sono saltati se si
    leggono stringhe
                                               4
Stream state

    Ciascun (i/o)stream ha un proprio


    stato

        Insieme di flag (valori booleani)
    



    Errori e condizioni non standard sono


    gestiti assegnando o controllando in
    modo appropriato lo stato


                                            5
End Of File (EOF)
                                   (EOF)
    Classica condizione che impedisce di


    effettuare ulteriori operazioni: leggere
    la marca EOF da uno stream di input
        Nel caso in cui si stia effettivamente
    

        leggendo un file attraverso l'istream,
        vuol dire che si è raggiunta la fine del
        file
        Nel caso di input da un terminale
    

        UNIX, l'EOF è generato se si preme
        Ctrl-D (su riga vuota)
                                              6
Espressioni con >>
    cin e cin>>..., oppure               !cin   e


    !(cin>>...) sono espressioni
        Es.:, cin>>dim è una espressione che ha
    

        un suo valore di ritorno
        Ovviamente come sappiamo la valutazione
    

        di tale espressione comporta la lettura da
        cin mediante l'operatore >>, e quindi
        l'assegnamento alla variabile dim di un
        opportuno valore in base al contenuto (e
        come vedremo allo stato) del cin


                                                7
Controllo stato istream
    Le precedenti espressioni si possono


    utilizzare dove è atteso un valore booleano,
    ed in tal caso il significato del loro valore è il
    seguente
        Vero: la prossima operazione può aver
    

        successo perché lo stream è in stato buono
        Falso: la prossima operazione fallirà perché
    

        lo stream è in stato non-buono
         Il motivo per lo stato non-buono è che

          l'ultima operazione è fallita: formato
          errato dell'input oppure incontrato EOF

                                                    8
Stato istream
    Una volta in stato non-buono, lo


    stream ci rimane finché i flag non sono
    esplicitamente resettati
    Semplice istruzione per resettare lo


    stato dello stream:
    cin.clear() ;
    Operazioni di input su stream in stato


    non-buono sono operazioni nulle
    Bisogna resettare prima di effettuare


    la prossima operazione di input
                                          9
Esercizio
    Scrivere un programma che, dopo aver


    letto da stdin una sequenza di numeri
    interi, stampi la somma dei valori letti
    La lunghezza della sequenza non è


    nota a priori, nè comunicata prima
    di iniziare ad immettere i numeri
    Soluzione nella prossima slide





                                          10
Esercizio
#include <iostream>

using namespace std ;

main()
{
     int i, somma = 0 ;
     while (cin>>i)
          somma += i ;
     cout<<quot;Somma: quot;<<somma<<endl ;
     // se volessi continuare ad usare
     // il cin, dovrei prima invocare
     // cin.clear()
}

                                         11
Operazioni di input nulle
    Come già detto, quando una operazione


    di input fallisce, è una vera e propria
    operazione nulla:
        nessun carattere è rimosso dallo
    

        stream di input
        il valore della variabile di destinazione è
    

        lasciato inalterato
    Esempio:

    int i = 3 ;
    cin>>i ; //   se   il cin è in stato di errore,
             //   in   i rimane 3 indipendentemen-
             //   te   dal contenuto dello stdin
                                                  12
Output streams
    ostream: meccanismo per convertire valori


    di vario tipo in sequenze di caratteri

        Output formattato
    


    standard output ostream e standard


    error ostream: cout e cerr
        ostream tipicamente collegati al terminale
    

        da cui è fatto partire il programma

        appartengono al namespace std
    



                                                13
Operazioni di uscita 1/2
    Supponiamo per un momento che all'interno


    dell'oggetto cout vi sia del codice che scriva
    immediatamente su stdout ogni singolo
    carattere ad esso passato mediante
    l'operatore <<
    Questo comporterebbe la lettura separata di


    ciascuno di tali caratteri da parte della shell
    da cui abbiamo lanciato il programma
    La shell a sua volta passerebbe uno ad uno i


    i caratteri letti terminale, che si
    occuperebbe a sua volta di comunicare col
    sistema operativo per farli apparire (di
    nuovo uno alla volta)
                                                  14
Operazioni di uscita 2/2
    Ciascuna delle precedenti operazioni su


    singolo carattere avrebbe più o meno lo
    stesso costo se effettuata su un intera
    stringa
    Allora perché non cercare di effettuarle


    per stringhe di più di un carattere
    anziché carattere per carattere?
    Una possibilità sarebbe ad esempio


    quella di mandare su stdout una riga alla
    volta, ossia una stringa che ha un
    newline come ultimo carattere
                                               15
Buffer 1/2
    A questo scopo potremmo immaginare


    che l'oggetto cout memorizzi
    temporaneamente i caratteri che gli
    vengono passati in un proprio array di
    caratteri, e li scriva effettivamente sullo
    stdout solo quando quest'array di
    caratteri arriva a contenere una riga
    Tutte le precedenti operazioni non


    sarebbero più effettuate per ogni singolo
    carattere, ma una riga alla volta
    Molto più efficiente


                                                  16
Buffer 2/2
    Tale array di caratteri è un esempio di


    buffer
    Si indica col termine buffer (memoria


    tampone) un array di byte utilizzato
    nelle operazioni di I/O
        Vi si memorizzano temporaneamente
    

        le informazioni prime di spostarle
        nella destinazione finale
        Il motivo principale per l'uso di un
    

        buffer è l'efficienza
                                               17
Uscita bufferizzata
    Le operazioni di uscita con gli stream


    sono effettivamente tipicamente
    bufferizzate
    Ad esempio il passaggio dei caratteri


    da stampare allo stdout non avviene
    carattere per carattere, bensì i
    caratteri vengono spediti tutti assieme
    proprio quando si inserisce il newline



                                             18
Buffer e incoerenza dell'uscita
    Si possono però avere problemi di


    incoerenza delle informazioni in uscita
        Ad esempio se un programma fallisce
    

        dopo una scrittura su cout in cui non
        si    è   inserito  il  newline,     i
        corrispondenti caratteri potrebbero
        non essere mai passati allo stdout
    Vederemo a breve un problema simile


    con le scritture su file

                                            19
Svuotamento del buffer
    Si può scatenare lo svuotamento del


    buffer anche senza l'invio del newline
     endl    inserisci un newline e svuota
              il   buffer   di   uscita    (la
              soluzione con il newline che
              conosciamo già)
     flush   svuota il buffer di uscita
              (senza    aggiungere      alcun
              carattere)
              Es.:
              cout<<quot;Provaquot;<<flush ;
                                            20
Due argomenti extra
    I prossimi due argomenti, ossia


    rimuovere i caratteri da stdin e
    formattare l'output, non saranno
    argomento d'esame




                                       21
Rimuovere caratteri da stdin

    Si possono rimuovere


    incondizionatamente caratteri da un
    istream con la seguente funzione

        cin.ignore() ignora, ossia rimuove, il
    

                     prossimo carattere da
                     stdin

    Vediamone l'uso con un esempio




                                            22
Soluzione non sicura
int main()
{
   int *p ; // attenzione, per ora contiene un valore casuale !!!
   int dim = -1 ;

    do { // immissione dimensioni array
      cout<<quot;Dimensioni array? quot; ;
                                    Che succede se si immette
      cin>>dim ;
                                       un carattere anziché una
    } while (dim < 0) ;
                                                                    cifra?
    p = new int[dim] ; // allocazione memoria

    ...
}




                                                                         23
Una soluzione sicura
int main()
{
   int *p ; // attenzione, per ora contiene un valore casuale !!!
   int dim = -1 ;

    do { // immissione dimensioni array
      cout<<quot;Dimensioni array? quot; ;
      while(!(cin>>dim)) {
                                                              Però non
             cin.clear() ;
                                                                esce in
             cin.ignore();
                                                                caso di
             cout<<quot;Devi immettere un numero: quot; ;
      }
                                                                  EOF!
    } while (dim < 0) ;
                                                          La soluzione
                                                             è lasciata
    p = new int[dim] ; // allocazione memoria
                                                                     al
    ...
                                                             lettore ...
}



                                                                      24
Formattazione dell'output
    Come già detto i seguenti argomenti di


    formattazione dell'output non saranno
    argomento di esame




                                         25
Esempio di output formattato
What's your name? Paolo
Health (in hundredths)? 35
Welcome to GOTA, Paolo. And good luck!


Giustificato
                              Lunghezza proporzionale
a sinistra
                              agli health points
Paolo---------------------------------------------------------------
| Health points: 035/100| ######                                      |
|---------------------------------------------------------------------|

               80 colonne (obbligatorio)
>

                                                                          26
Formattazione dell'Output
    La formattazione è controllata da un


    insieme di flag e valori interi

    Semplice interfaccia per assegnare tali


    valori: funzioni dedicate e manipolatori




                                          27
setprecision
    cout.setprecision(int n)


    Setta il massimo numero di cifre per
    un numero in virgola mobile

        l'effettivo output dipende dal formato
    

        (generale, scientifico, fisso)

        l'effetto è persistente: influenza tutte
    

        le prossime operazioni di uscita, fino
        alla prossima evetuale chiamata di
        setprecision
                                              28
Manipolatore
    Operazione che modifica lo stato, da


    passare       agli      operatori  di
    ingresso/uscita allo stesso modo degli
    oggetti che si da scrivere/leggere

    Esempi (già visti) di manipolatori che


    non prendono argomenti:
        flush   svuota il buffer di uscita
    

        endl    inserisci un newline e svuota
    

                il buffer di uscita
                                             29
Manipolatori con argom. 1/2
    Spesso si vuole riempire con del testo


    predefinito un certo spazio su una
    linea

    cout<<...<<setw(int n)<<...



    Setta il minimo numero di caratteri per
    la prossima operazione di uscita

    cout<<...<<setw(...)<<setfill(char c)<<...



    Sceglie il carattere in c come carattere
    di riempimento
                                                 30
Manipolatori con argom. 2/2
    Per usare manipolatori che prendono


    argomenti bisogna includere:

    #include <iomanip>




                                          31
Stampa dello stato del gioco
#include <iostream>
#include <iomanip>

using namespace std ;

int main()
{
  int punti_salute = 35 ;

 cout<<left<<setw(80)<<setfill('-')<<quot;Paoloquot;<<endl ;
                      cout<<quot;|         Health        points:
   quot;<<right<<setw(3)<<setfill('0')<<punti_salute<<quot;/100 | quot; ;
 int num_asterischi = punti_salute*51/100 ;
 cout<<setw(num_asterischi)<<setfill('#')<<quot;quot; ;
 cout<<setfill(' ') ;
 cout<<setw(53 - num_asterischi)<<right<<quot; |quot;<<endl ;
 cout<<setw(80)<<setfill('-')<<quot;quot;<<endl ;

  return 0 ;
}

                                                                32
Torniamo agli argomenti che


    saranno oggetto d'esame ...




                                  33
Definizione di nuovi stream
    cout, cerr, cin sono già pronti all'uso


    quando un programma parte

    Sono creati automaticamente ed


    associati allo stdout, stdin e stderr del
    programma
    Però possiamo anche creare i nostri


    stream
     Alla creazione di uno stream dobbiamo

      specificare l'oggetto a cui è associato
     Un tipico oggetto a cui associare uno

      stream è un file
                                                34
fstream
    I seguenti tipi di stream sono da


    associare ai file, e sono supportati
    direttamente dalla libreria standard del
    C++ (non da quella del C)
    ifstream: file stream di ingresso (lettura)



    ofstream: file stream di uscita (scrittura)



    fstream: file stream di ingresso/uscita



    Presentati in <[i | o]fstream> o in


    <fstream> (tutti e tre)
                                              35
Modello di file
    Un file è visto come una sequenza di


    caratteri (byte) che, come vedremo,
    potrà essere letta attraverso un ifstream
    (o uno fstream opportunamente
    inizializzato) o modificata attraverso un
    ofstream (o di nuovo uno fstream
    opportunamente inizializzato)




                                                36
Associazione a file
    Un (i|o)fstream viene associato ad un file


    mediante un'operazione chiamata
    apertura del file
        Da quel momento in poi tutte le
    

        operazioni di ingresso/uscita fatte sullo
        stream si tradurranno in identiche
        operazioni sul contenuto del file
        E' il sistema operativo che si occuperà di
    

        tutti i dettagli (che variano da sistema a
        sistema) necessari per eseguire le
        operazioni sulla macchina reale
                                                37
Associazione a file
    Come nome del file si può indicare tanto un


    percorso assoluto che un percorso relativo
    Esempio di percorso assoluto:


    /home/paolo/dati.txt
    File di nome dati.txt nella cartella /home/paolo
    Esempi di percorsi relativi (il file è cercato


    nella cartella corrente):
    paolo/dati.txt
    File di nome dati.txt nella sottocartella paolo
    della cartella corrente

    dati.txt
    File di nome dati.txt nella cartella corrente
                                                    38
Associazione a file
    E' possibile aprire più di un file


    contemporaneamente
    L'apertura di un file può fallire per


    diversi motivi
        Ad esempio se si tenta di aprire in
    

        lettura un file inesistente
    E' opportuno controllare sempre l'esito


    dell'operazione di apertura prima di
    utilizzare un (i|o)fstream

                                              39
Apertura file 1/3
    Un file è aperto in input definendo un


    oggetto di tipo ifstream e passando il
    nome del file come argomento
    ifstream f(“nome_file”) ;
    if (!f) cerr<<”l'apertura è fallitan” ;
    Un file è aperto in output definendo un


    oggetto di tipo ofstream e passando il
    nome del file come argomento
    ofstream f(“nome_file”) ;
    if (!f) cerr<<”l'apertura è fallitan” ;

                                               40
Apertura file 2/3
    Un file può essere aperto per l'ingresso


    e/o l'uscita definendo un oggetto di tipo
    fstream e passando il nome del file come
    argomento
    Deve essere fornito un secondo


    argomento openmode
        ios_base::in oppure ios_base::out
    


    Se non esiste, un file aperto in scrittura


    viene creato, altrimenti viene troncato a
    lunghezza 0
                                                 41
Apertura file 3/3
    Esempi:



    // file aperto in ingresso
    fstream f(“nome_file”, ios_base::in) ;
    if (!f) cerr<<”apertura fallitan” ;

    // file aperto in uscita
    fstream f2(“nome_file”, ios_base::out) ;
    if (!f) cerr<<”apertura fallitan” ;




                                               42
Gerarchia degli stream
                     ios_base
                         deriva da
                       ios

                                ostream
           istream

                                      ofstream
ifstream             iostream



                     fstream


                                                 43
Conseguenza immediata
    Si possono usare tutti gli operatori, i flag


    di stato, e le funzioni di utilità per la
    formattazione viste per gli stream di
    ingresso/uscita standard

    Quindi si può quindi controllare lo stato di


    un oggetto (i|o)fstream f usando il suo
    identificatore in una espressione
    condizionale
    Esempio:
    if (!f)
         cerr<<”La precedente operazione è”
             <<”fallita”<<endl ;
                                                   44
Informazioni aggiuntive
    Come visto negli esempi, con oggetti di


    tipo ifstream, ofstream o fstream si
    controlla il successo o meno dell'apertura
    controllando lo stato
    Più modi possono essere combinati


    mediante l'operatore |
    in: input, out: output, app: append (si


    continua a scrivere a partire dal fondo)
    ofstream f(“nome_file”, ios_base::app) ;


                                               45
Bufferizzazione uscita
    Per gli stessi motivi di efficienza visti per


    gli ostream collegati allo stdout, anche le
    operazioni di uscita su ofstream (oppure
    fstream inizializzati in scrittura) sono
    tipicamente bufferizzate
    Quindi, a meno di passare ad esempio i


    manipolatori endl e/o flush non è
    garantito che una certa scrittura sia
    immediatamente effettuata sul file
    associato

                                                46
Chiusura file
    Un file può essere chiuso invocando la


    funzione close() sullo stream ad esso
    associato
    Es.: f.close() ;

    Un file è comunque chiuso implicitamente


    alla distruzione dello stream associato


    La chiusura (esplicita o implicita) di un file è


    importante perché solo all'atto della
    chiusura ne è garantito l'effettivo
    aggiornamento (svuotamento dei buffer)
                                                   47
open
    Si può anche aprire un file invocando la


    funzione open su uno stream non ancora
    associato ad alcun file (non inizializzato o
    deassociato mediante close)
        Per brevità non vedremo la open in queste
    

        lezioni




                                                    48
Esercizio
    file/file.cc





                          49
Domanda
    Siete riusciti a risolvere l'esercizio in


    modo completo?
    Probabilmente no, perché l'operatore


    >> ha saltato i caratteri 'n'
    Vedremo a breve la soluzione mediante


    I/O non formattato




                                                50
Esercizio
    Leggere da un file di testo dati.txt una


    sequenza di numeri interi di al più 100
    elementi, finché non si trova il primo
    elemento uguale a 0. Memorizzare tutti
    i numeri letti in un vettore.




                                               51
Soluzione
main()
{
  int vett[100] ;
  ifstream f(quot;dati.txtquot;);
  if (!f)
       cerr<<quot;Errore di apertura filenquot;;
  else
       for (int i = 0 ; i < 100 && f>>vett[i]
                  && vett[i] != 0 ; i++)
                  ;
}




                                                52
Esercizi (senza soluzione)
    ESERCIZIO 1: Leggere da un file di testo dati.txt una


    sequenza di numeri interi terminata da 0.
    Memorizzare in un vettore tutti i numeri negativi.

    ESERCIZIO 2: Leggere da un file di testo dati.txt una


    sequenza di numeri interi terminata da 0.
    Memorizzare in un vettore tutti i numeri compresi
    tra –30 e +30 escluso lo 0. Ordinare il vettore in
    modo crescente e stampare tutti i numeri positivi.

    ESERCIZIO 3: Leggere da un file di testo dati.txt una


    sequenza di caratteri terminata da *. Memorizzare
    in un vettore tutti i caratteri alfabetici.


                                                       53
Esercizio
    Scrivere in un file di testo valori_pos.txt tutti


    i numeri strettamente positivi di un vettore
    contenente N valori interi, con N definito a
    tempo di scrittura del programma.
    Alla fine, inserire il valore -1 come
    terminatore.




                                                    54
Soluzione
main()
{
  const int N = 10 ;
  int vett[N] ;
   ofstream f(“dati.txt”);
   if (!f)
       cerr<<”Errore di apertura filenquot;;
    else {
       for (int i=0; i<N; i++)
                 if (vett[i]>0)
             f<<vett[i];

            f<<-1 ;
        }
}



                                            55
Esercizi (senza soluzione)
    ESERCIZIO 1: Scrivere in un file di testo “carat.txt”


    tutti i caratteri di una stringa letta da input.
    Terminare la sequenza di caratteri del file con *.

    ESERCIZIO 2: Leggere da un file di testo


    “dati_inp.txt” una sequenza di numeri interi
    terminata da 0, e copiare in un vettore solo gli
    elementi positivi. Copiare tutti i valori del vettore
    compresi fra 10 e 100 in un file di testo
    “dati_out.txt”.

    ESERCIZIO 3: Come l’esercizio 4.c. In più, stampare


    su schermo il contenuto del file “dati_out.txt”.


                                                            56
I/O formattato
    Gli operatori di ingresso/uscita visti


    finora, ossia >> e <<, interpretano il
    contenuto di uno stream come una
    sequenza di caratteri
    Traducono quindi valori in caratteri e


    viceversa
    Le operazioni di ingresso/uscita in cui


    uno stream è visto come una sequenza
    di caratteri si definiscono operazioni di
    ingresso/uscita formattate
                                                57
I/O non formattato
    Esistono anche operazioni di ingresso/


    uscita non formattate
    Vedono lo stream come una mera


    sequenza di byte e non effettuano
    alcuna trasformazione di alcun tipo
        Trasferiscono semplicemente sequenze
    

        di byte da uno stream ad un array di
        byte (o un singolo byte), o da un array
        di byte (o un singolo byte) ad uno
        stream
                                             58
Funzioni membro
    Le funzioni di lettura e scrittura non


    formattate che vedremo sono delle funzioni
    membro
    Per utilizzarle bisogna usare la notazione a


    punto
        Se f è un istream, allora per usare ad
    

        esempio una funzione membro fun(char
        &), bisogna scrivere f.fun(c) ;
        Es.:
        char c ;
        cin.fun(c) ;

                                                   59
Buffer ed I/O non formattato
    Come già visto, un buffer è un array


    di byte utilizzato nelle operazioni di I/O
    Il tipo char ha esattamente la


    dimensione di un byte
    Per questo motivo il tipo char è


    utilizzato anche per memorizzare byte
    nelle letture e le scritture non
    formattate


                                             60
Input non formattato
    Gli istream dispongono delle seguenti


    funzioni membro per input non
    formattato:
    get()
    get(char &)
    get(char   *buffer, int n,
        char   delimitatore='n')
    read(char *buffer, int n)
    gcount()
                                            61
get()
    Ritorna, su un int, il valore del


    prossimo byte nello stream di ingresso a
    cui è applicata
        Ritorna il valore EOF in caso di fine input
    

 Esempio:


main()
{
    int i = cin.get() ;
    ...
}
                                                      62
get(char &c) 1/2
    Preleva un byte e lo assegna alla


    variabile passata come argomento
        La variabile è lasciata inalterata in caso di
    

        fine input
  Esempio:


main()
{
 char c ;
 cin.get(c) ;
 ...
}
                                                        63
get(char &c) 2/2
    Per semplicità, diciamo che ritorna lo istream a


    cui è applicata

    Quindi si può usare allo stesso modo di uno


    istream in espressioni che si aspettano un
    booleano
  Esempio:


main()
{
 char c ;
 while(cin.get(c))
       ...
}
                                                   64
Esercizio
    file/file_conta_linee.cc





                                      65
Lettura in un buffer
get(char *buffer, int n,
     char delimitatore='n')
    Legge byte dallo stream di ingresso e li


    trasferisce in buffer aggiungendo il
    carattere '0' finale
    La lettura va avanti finché non si sono


    letti n byte oppure non è stato
    incontrato il delimitatore
        Se il terzo argomento non è passato, si usa
    

        come delimitatore il codice del carattere 'n'
                                                    66
Esempio di lettura in un buffer
main()
{
 char buf[100] ;

 // lettura di al più 50 byte, a meno
  // non si incontri il codice del
 // carattere '-'
 // in fondo è inserito '0'
 cin.get(buf, 50, '-') ;
  ...
}

                                        67
Lettura in un buffer 2
read(char *buffer, int n)
        Legge n byte e li memorizza nell'array
    

        buffer

        Non è previsto alcun delimitatore, né
    

        aggiunto alcun terminatore

gcount()
    Ritorna il numero di caratteri letti


    nell'ultima operazione di lettura

                                                 68
Scrittura non formattata
put(char c)
    Trasferisce un byte (il contenuto di c)


    sullo stream di uscita

write(const char *buffer, int n)
    Trasferisce i primi n byte di buffer


    sullo stream di uscita
    Non è inserito alcun terminatore




                                              69
File di testo e file binari 1/2
    Se si effettuano solo letture e scritture


    formattate su uno stream, si dice che lo
    si sta usando in modo testo
    In maniera simile, come già sappiamo,


    un file i cui byte sono da interpretarsi
    come codici di caratteri si definisce un
    file di testo
    Altrimenti si usa tipicamente la


    denominazione file binario

                                            70
File di testo e file binari 2/2
    Per lavorare con file binari sono


    estremamente comode le
    letture/scritture non formattate, perché
    permettono appunto di ragionare in
    termini di pure sequenze di byte
    Ricordare sempre però che un file


    rimane comunque solo una sequenza di
    byte, ed il fatto che sia un file di testo o
    un file binario è solo una questione di
    come è da interpretare tale sequenza di
    byte
                                               71
Puntatori ed array
    Estendiamo le nostre conoscenze


    Come sappiamo il tipo puntatore


    <tipo> *
    memorizza indirizzi
    Come mai possiamo passare un array


    come argomento attuale nella posizione
    corrispondente ad un parametro formale
    di tipo <tipo> * ?
    Perché passare il nome di un array è


    equivalente a passare l'indirizzo del
    primo elemento dell'array
                                             72
Esempio con tipo char
void fun(const char *a)
{
  ofstream f(quot;nomequot;) ;
  // trasferiamo due elementi,
  // ossia due byte dell'array a
  f.write(a, 2) ;
}

main()
{
  char b[3] = {14, 31, 66} ;
  fun(b) ; // passo l'indirizzo di b
}
                                   73
Oggetti e puntatori
    Il tipo char * memorizza indirizzi


        Possiamo scriverci dentro l'indirizzo di
    

        qualsiasi oggetto, dinamico o non
        dinamico, non solo quindi di un array
        dinamico
        In particolare, possiamo anche scriverci
    

        dentro l'indirizzo di oggetti di tipo diverso
        da array di caratteri




                                                    74
Trasferimento oggetti generici
    Le funzioni di ingresso/uscita non formattate


    si aspettano però solo array di caratteri

    Per usare tali funzioni dobbiamo perciò


    convertire il tipo dell'indirizzo di un oggetto
    diverso da un array di caratteri mediante:
reinterpret_cast<char *>(<indirizzo>)
        Si può anche aggiungere il const
    


        Proviamo a vedere il significato logico di
    

        tale conversione


                                                      75
Oggetti in memoria 1/3
    Consideriamo ad esempio un array di interi


    di 3 elementi:


    Supponendo che ogni elemento occupi 4


    byte, l'array in memoria sarà fatto così:



    Si tratta di una tipica sequenza di byte





                                                 76
Oggetti in memoria 2/3
    Tale sequenza di byte ha qualche differenza


    intrinseca rispetto ad una qualsiasi altra
    sequenza di byte di pari lunghezza?




                                              77
Oggetti in memoria 3/3
    No



    Prendendo in prestito dal C/C++ il termine


    array, possiamo dire che una sequenza di
    byte non è altro che un array di byte

    Ma sappiamo che un byte può essere


    rappresentato esattamente su di char

    Quindi, qualsiasi sequenza di byte può


    essere rappresentata con array di char



                                                 78
Significato conversione
    Pertanto


reinterpret_cast<char *>(<indirizzo_oggetto>)
        Da un punto di vista logico vuol dire:
    

        “Interpreta come una sequenza di byte il
        contenuto della memoria a partire
        dall'indirizzo dell'oggetto”
    Rimane il problema di sapere la lunghezza di


    tale sequenza di byte
        Non solo, in generale potremmo voler
    

        trasferire una sequenza di byte, ossia un
        array di caratteri, relativa solo ad una
        porzione dell'intero oggetto
                                                    79
Dimensioni in byte 1/2
    Dato un generico array di elementi di


    qualche tipo, possiamo calcolare la
    lunghezza della sequenza di byte
    occupati da un certo numero di elementi
    dell'array nel seguente modo
    Utilizziamo l'operatore sizeof per


    conoscere le dimensioni di ogni elemento, e
    moltiplichiamo per il numero di elementi



                                              80
Dimensioni in byte 2/2
    Consideriamo di nuovo un array di interi di 3


    elementi e supponiamo che'operatore sizeof
    ci dica che ogni elemento occupa 4 byte:


         4 byte    4 byte     4 byte

    L'array in memoria occupa 4x3=12 byte





         4 byte    4 byte     4 byte


                                                81
Scrittura intero array
void scrivi_array_su_file(const int *a)
{
  ofstream f(quot;file_destinazionequot;) ;
  f.write(
     reinterpret_cast<const char *>(a),
     sizeof(int) * 3
     );
}

main()
{
     int b[3] = {1, 2, 7} ;
     scrivi_array_su_file(b) ;
}
                                          82
Scrittura su file binari
    Cosa abbiamo fatto?



    Abbiamo scritto nel file di nome


    file_destinazione la rappresentazione
    in memoria, byte per byte, dell'array di
    interi b
    file_destinazione sarà certamente un


    file binario
    Esercizio: file/scrivi_leggi_array.cc




                                            83
Domanda
    Potevamo scrivere gli elementi uno


    alla volta nel file binario?




                                         84
Bufferizzazione
    Sì, ma sarebbe stato molto inefficiente



    Abbiamo dovuto invece scrivere gli


    elementi uno alla volta nel caso del file
    di testo
        Ma l'efficienza non si è persa, perché,
    

        come già detto, ci ha pensato
        l'operatore di uscita a bufferizzare le
        informazioni al posto nostro



                                                85
Passaggio indirizzo
    Come abbiamo visto, il nome di un


    array in una espressione denota
    l'indirizzo di un array
    Pertanto passare un array come


    parametro formale equivale a passare
    l'indirizzo dell'array
    E se volessimo passare ad una delle


    funzioni di ingresso/uscita l'indirizzo di
    un oggetto diverso da un array?
        Ad esempio un singolo intero, o un
    

        singolo oggetto di tipo struttura?
                                                 86
Operatore indirizzo
    In questo caso dovremmo utilizzare


    l'operatore indirizzo &
    Si tratta di un operatore unario prefisso



    Sintassi


    & <nome_oggetto>
    Semantica: ritorna l'indirizzo


    dell'oggetto passato per argomento
    Come sarà fatto l'oggetto in memoria?





                                                87
Generico oggetto in memoria
    Consideriamo un generico oggetto, per


    esempio di tipo strutturato


    Se l'oggetto occupa ad esempio 8 byte,


    allora in memoria si avrà la seguente
    sequenza di byte a partire dall'indirizzo
    dell'oggetto:


    Come già sappiamo, è una tipica sequenza


    di byte, rappresentabile mediante un array
    di caratteri
                                                 88
Esempio con struct 1/2
main()
{
 struct part {char nome[10]; int tempo}
       mario ;

 strcpy(mario.nome, quot;Marioquot;) ;
 mario.tempo = 30 ;
 char * const p =
      reinterpret_cast<char *>(& mario) ;
}

         Use dell'operatore & per ritornare
         l'indirizzo dell'oggetto
                                            89
Esempio con struct 2/2
    In p è finito l'indirizzo in memoria


    dell'oggetto struttura mario
    La conversione si è resa necessaria perché


    p punta ad oggetti di tipo diverso
    Come facciamo ad accedere solo


    all'effettivo numero di byte occupati da
    mario?
    Utilizziamo l'operatore sizeof




                                               90
Scrittura su file binari 1/2
main()
{
 struct part {char nome[10]; int tempo}
       mario ;

 strcpy(mario.nome, quot;Marioquot;) ;
 mario.tempo = 30 ;
 char * const p =
      reinterpret_cast<char *>(& mario) ;
 ofstream f(quot;dati.datquot;) ;
 f.write(p, sizeof(mario)) ;
}

                                            91
Scrittura su file binari 2/2
    Cosa abbiamo fatto?



    Abbiamo scritto nel file dati.dat la


    rappresentazione in memoria, byte per
    byte, dell'oggetto mario
    dati.dat è certamente un file binario





                                            92
Lettura da file binari
    Come facciamo a rimettere in memoria le


    informazioni salvate nel file?
    file_binario.cc



    Prima di andare avanti è opportuno


    osservare che quanto fatto con un
    oggetto di tipo struct è solo un altro
    esempio di lettura/scrittura da/su file
    binario
    Si potevano fare esempi con matrici o


    array di oggetti struttura, e così via ...
                                                 93
Accesso sequenziale e casuale
    Uno stream è definito ad accesso


    sequenziale se ogni operazione
    interessa caselle dello stream
    consecutive a quelle dell'operazione
    precedente
    Uno stream è definito ad accesso


    casuale se per una operazione può
    essere scelta arbitrariamente la
    posizione della prima casella coinvolta
    Per cin, cout e cerr è definito solo


    l'accesso sequenziale
                                           94
Accesso casuale ai file
    La casella a partire dalla quale avverrà la


    prossima operazione è data da un
    contatore che parte da 0 (prima casella)
    Il suo contenuto può essere modificato


    con le funzioni membro
    seekg(nuovo_valore) per file in ingresso
                       (la g sta per get)
    seekp(nuovo_valore) per file in uscita
                       (la p sta per put)


                                              95
Accesso casuale ai file
    Le due funzioni possono anche essere


    invocate con due argomenti
    seekg(offset, origine)
    seekp(offset, origine)
    L'origine può essere:


    ios::beg offset indica il numero di posizioni
     a partire dalla casella 0 (equivalente a non
     passare un secondo argomento)
    ios::end offset indica il numero di posizioni
     a partire dall'ultima casella (muovendosi
     all'indietro)
                                                96
Lettura della posizione
    Per gli ifstream è definita la funzione


     tellg()
     Ritorna il valore corrente del contatore
    Per gli ofstream è definita la funzione


     tellp()
     Ritorna il valore corrente del contatore




                                                97
Passaggio di stream 1/2
    Uno stream può essere passato per


    riferimento ad una funzione
    cin può essere passato come parametro
    attuale in corrispondenza di un parametro
    formale di tipo istream &
    cout può essere passato come parametro
    attuale in corrispondenza di un parametro
    formale di tipocome ostream &




                                                98
Passaggio di stream 2/2
    Gli (i|o)fstream possono essere passati per


    riferimento dove sono attesi gli (i|o)stream
    un ifstream può essere passato come
    parametro attuale in corrispondenza di un
    parametro formale di tipo istream &
    un ofstream può essere passato come
    parametro attuale in corrispondenza di un
    parametro formale di tipo ostream &




                                                   99
Esempio
void stampa(ostream &o) {
 o<<quot;Stringaquot;<<endl ; }

void leggi(istream &i) {
 char s[100] ;
 i>>s ; cout<<s<<endl ; }

main()
{
  stampa(cout) ; // stampa su stdout
 ofstream f(quot;nome_file.txtquot;) ;
 stampa(f) ; // scrive nel file
 leggi(cin) ; // legge da stdin
 ifstream f2(quot;nome_file.txtquot;) ;
 leggi(f2) ; // legge dal file
}
                                            100
Esercizio
    Dato un file binario in cui sono


    memorizzati oggetti di tipo

    struct   persona {
                 char      codice[7];
                 char      Nome[20];
                 char      Cognome[20];
                 int       Reddito;
                 int       Aliquota;
             };

    ed assumendo che ogni persona abbia un
    codice univoco ...                   101
Esercizio
    Scrivere una funzione che prenda in ingresso


    un oggetto P di tipo persona per riferimento,
    ed un istream che contiene la
    rappresentazione binaria di una sequenza di
    oggetti di tipo persona.
    La funzione cerca nello istream un oggetto
    con lo stesso valore del campo codice
    dell'oggetto P e, se trovato, riempie i restanti
    campi dell'oggetto P con i valori dei
    corrispondenti campi dell'oggetto trovato nel
    file.
    La funzione ritorna true in caso di successo,
    ossia se l'oggetto è stato trovato, false
    altrimenti
                                                   102
Soluzione
bool ricerca_file(persona &P, istream &f)
{
  bool trovato=false;
    while (true) {
        persona buf[1] ;
        f.read(reinterpret_cast<char *>(buf),
                sizeof(persona)) ;
        if (f.gcount() <= 0)
              break ;
        if (strcmp(buf[0].Nome, P.Nome) == 0) {
              P = buf[0] ;
              trovato = true ;
              break ;
        }
  }
  return trovato;
}
                                                  103
Osservazioni finali 1/2
    I file sono una delle strutture dati


    fondamentali per la soluzione di problemi
    reali
    Infatti nella maggior parte delle applicazioni


    reali i dati non si leggono (solamente) da
    input e non si stampano (solamente) su
    terminale, ma si leggono da file e si salvano
    su file




                                                 104
Osservazioni finali 2/2
    Spesso si rende necessario gestire grandi


    quantità di dati su supporti di memoria
    secondaria in modo molto efficiente
        Gli informatici vedranno come negli
    

        insegnamenti di “BASI DI DATI”
    Ricordare infine che la gestione dei file sarà


    sempre parte della prova di
    programmazione




                                                 105

Weitere ähnliche Inhalte

Was ist angesagt?

10 - Programmazione: Tipi di dato strutturati
10 - Programmazione: Tipi di dato strutturati10 - Programmazione: Tipi di dato strutturati
10 - Programmazione: Tipi di dato strutturati
Majong DevJfu
 
[Ebook ita - security] introduzione alle tecniche di exploit - mori - ifoa ...
[Ebook   ita - security] introduzione alle tecniche di exploit - mori - ifoa ...[Ebook   ita - security] introduzione alle tecniche di exploit - mori - ifoa ...
[Ebook ita - security] introduzione alle tecniche di exploit - mori - ifoa ...
UltraUploader
 
12 - Programmazione: Array dinamici e puntatori
12 - Programmazione: Array dinamici e puntatori12 - Programmazione: Array dinamici e puntatori
12 - Programmazione: Array dinamici e puntatori
Majong DevJfu
 
Lezione 12 (28 marzo 2012)
Lezione 12 (28 marzo 2012)Lezione 12 (28 marzo 2012)
Lezione 12 (28 marzo 2012)
STELITANO
 
Lezione 12 (28 marzo 2012)
Lezione 12 (28 marzo 2012)Lezione 12 (28 marzo 2012)
Lezione 12 (28 marzo 2012)
STELITANO
 
08 - Programmazione: Passaggio valori tra funzioni per riferimenti
08 - Programmazione: Passaggio valori tra funzioni per riferimenti08 - Programmazione: Passaggio valori tra funzioni per riferimenti
08 - Programmazione: Passaggio valori tra funzioni per riferimenti
Majong DevJfu
 
06 1 array_stringhe_typedef
06 1 array_stringhe_typedef06 1 array_stringhe_typedef
06 1 array_stringhe_typedef
Piero Fraternali
 
05 - Programmazione: Funzioni
05 - Programmazione: Funzioni05 - Programmazione: Funzioni
05 - Programmazione: Funzioni
Majong DevJfu
 
9 Altre Istruzioni Di I O
9   Altre Istruzioni Di I O9   Altre Istruzioni Di I O
9 Altre Istruzioni Di I O
guest60e9511
 
11 - Programmazione: Tipi di dato strutturati pt. 2
11 - Programmazione: Tipi di dato strutturati pt. 211 - Programmazione: Tipi di dato strutturati pt. 2
11 - Programmazione: Tipi di dato strutturati pt. 2
Majong DevJfu
 
Lezione 5 (7 marzo 2012)
Lezione 5 (7 marzo 2012)Lezione 5 (7 marzo 2012)
Lezione 5 (7 marzo 2012)
STELITANO
 
Attacchi alle applicazioni basati su buffer overflow
Attacchi alle applicazioni basati su buffer overflowAttacchi alle applicazioni basati su buffer overflow
Attacchi alle applicazioni basati su buffer overflow
Giacomo Antonino Fazio
 
07 - Programmazione: Tipi di base e conversioni
07 - Programmazione: Tipi di base e conversioni07 - Programmazione: Tipi di base e conversioni
07 - Programmazione: Tipi di base e conversioni
Majong DevJfu
 
03 - Programmazione: Istruzioni C++
03 - Programmazione: Istruzioni C++03 - Programmazione: Istruzioni C++
03 - Programmazione: Istruzioni C++
Majong DevJfu
 
Laboratorio Programmazione: In - Out variabili
Laboratorio Programmazione: In - Out variabiliLaboratorio Programmazione: In - Out variabili
Laboratorio Programmazione: In - Out variabili
Majong DevJfu
 
Esercitazione 1 (27 febbraio 2012)
Esercitazione 1 (27 febbraio 2012)Esercitazione 1 (27 febbraio 2012)
Esercitazione 1 (27 febbraio 2012)
STELITANO
 

Was ist angesagt? (20)

10 - Programmazione: Tipi di dato strutturati
10 - Programmazione: Tipi di dato strutturati10 - Programmazione: Tipi di dato strutturati
10 - Programmazione: Tipi di dato strutturati
 
PHP 7 - benvenuto al futuro
PHP 7 - benvenuto al futuroPHP 7 - benvenuto al futuro
PHP 7 - benvenuto al futuro
 
[Ebook ita - security] introduzione alle tecniche di exploit - mori - ifoa ...
[Ebook   ita - security] introduzione alle tecniche di exploit - mori - ifoa ...[Ebook   ita - security] introduzione alle tecniche di exploit - mori - ifoa ...
[Ebook ita - security] introduzione alle tecniche di exploit - mori - ifoa ...
 
12 - Programmazione: Array dinamici e puntatori
12 - Programmazione: Array dinamici e puntatori12 - Programmazione: Array dinamici e puntatori
12 - Programmazione: Array dinamici e puntatori
 
Lezione 12 (28 marzo 2012)
Lezione 12 (28 marzo 2012)Lezione 12 (28 marzo 2012)
Lezione 12 (28 marzo 2012)
 
Lezione 12 (28 marzo 2012)
Lezione 12 (28 marzo 2012)Lezione 12 (28 marzo 2012)
Lezione 12 (28 marzo 2012)
 
08 - Programmazione: Passaggio valori tra funzioni per riferimenti
08 - Programmazione: Passaggio valori tra funzioni per riferimenti08 - Programmazione: Passaggio valori tra funzioni per riferimenti
08 - Programmazione: Passaggio valori tra funzioni per riferimenti
 
06 1 array_stringhe_typedef
06 1 array_stringhe_typedef06 1 array_stringhe_typedef
06 1 array_stringhe_typedef
 
05 - Programmazione: Funzioni
05 - Programmazione: Funzioni05 - Programmazione: Funzioni
05 - Programmazione: Funzioni
 
9 Altre Istruzioni Di I O
9   Altre Istruzioni Di I O9   Altre Istruzioni Di I O
9 Altre Istruzioni Di I O
 
Bash programming
Bash programmingBash programming
Bash programming
 
11 - Programmazione: Tipi di dato strutturati pt. 2
11 - Programmazione: Tipi di dato strutturati pt. 211 - Programmazione: Tipi di dato strutturati pt. 2
11 - Programmazione: Tipi di dato strutturati pt. 2
 
Lezione 5 (7 marzo 2012)
Lezione 5 (7 marzo 2012)Lezione 5 (7 marzo 2012)
Lezione 5 (7 marzo 2012)
 
Attacchi alle applicazioni basati su buffer overflow
Attacchi alle applicazioni basati su buffer overflowAttacchi alle applicazioni basati su buffer overflow
Attacchi alle applicazioni basati su buffer overflow
 
07 - Programmazione: Tipi di base e conversioni
07 - Programmazione: Tipi di base e conversioni07 - Programmazione: Tipi di base e conversioni
07 - Programmazione: Tipi di base e conversioni
 
3 Linguaggioc
3   Linguaggioc3   Linguaggioc
3 Linguaggioc
 
Attacchi alle applicazioni basati su buffer overflow
Attacchi alle applicazioni basati su buffer overflowAttacchi alle applicazioni basati su buffer overflow
Attacchi alle applicazioni basati su buffer overflow
 
03 - Programmazione: Istruzioni C++
03 - Programmazione: Istruzioni C++03 - Programmazione: Istruzioni C++
03 - Programmazione: Istruzioni C++
 
Laboratorio Programmazione: In - Out variabili
Laboratorio Programmazione: In - Out variabiliLaboratorio Programmazione: In - Out variabili
Laboratorio Programmazione: In - Out variabili
 
Esercitazione 1 (27 febbraio 2012)
Esercitazione 1 (27 febbraio 2012)Esercitazione 1 (27 febbraio 2012)
Esercitazione 1 (27 febbraio 2012)
 

Andere mochten auch (9)

Introduzione User Mode Linux
Introduzione User Mode LinuxIntroduzione User Mode Linux
Introduzione User Mode Linux
 
UE week 2
UE week 2UE week 2
UE week 2
 
Workplan
WorkplanWorkplan
Workplan
 
Pe t4 perl-oggetti
Pe t4 perl-oggettiPe t4 perl-oggetti
Pe t4 perl-oggetti
 
Pe a1 perl-unit_testing
Pe a1 perl-unit_testingPe a1 perl-unit_testing
Pe a1 perl-unit_testing
 
C6es
C6esC6es
C6es
 
T2 architettura
T2 architetturaT2 architettura
T2 architettura
 
Campeggi pola medulin
Campeggi pola medulinCampeggi pola medulin
Campeggi pola medulin
 
PF for medical scrubs and lab coats
PF for medical scrubs and lab coatsPF for medical scrubs and lab coats
PF for medical scrubs and lab coats
 

Ähnlich wie 14 - Programmazione: Stream e File

13 - Programmazione: Compendio C - C++
13 - Programmazione: Compendio C - C++13 - Programmazione: Compendio C - C++
13 - Programmazione: Compendio C - C++
Majong DevJfu
 
Laboratorio Programmazione: Visibilita' e tipi di dato
Laboratorio Programmazione: Visibilita' e tipi di datoLaboratorio Programmazione: Visibilita' e tipi di dato
Laboratorio Programmazione: Visibilita' e tipi di dato
Majong DevJfu
 
Caratteristiche del linguaggio c
Caratteristiche del linguaggio cCaratteristiche del linguaggio c
Caratteristiche del linguaggio c
ughetta
 
Sistemi Operativi: Il kernel linux - Lezione 06
Sistemi Operativi: Il kernel linux - Lezione 06Sistemi Operativi: Il kernel linux - Lezione 06
Sistemi Operativi: Il kernel linux - Lezione 06
Majong DevJfu
 
2 Linux Comandi Essenziali
2 Linux Comandi Essenziali2 Linux Comandi Essenziali
2 Linux Comandi Essenziali
Mauro Ferrigno
 
Lezione 11 (26 marzo 2012)
Lezione 11 (26 marzo 2012)Lezione 11 (26 marzo 2012)
Lezione 11 (26 marzo 2012)
STELITANO
 
Pycrashcourse3.1
Pycrashcourse3.1Pycrashcourse3.1
Pycrashcourse3.1
rik0
 
Lezione 6 (12 marzo 2012)
Lezione 6 (12 marzo 2012)Lezione 6 (12 marzo 2012)
Lezione 6 (12 marzo 2012)
STELITANO
 

Ähnlich wie 14 - Programmazione: Stream e File (20)

13 - Programmazione: Compendio C - C++
13 - Programmazione: Compendio C - C++13 - Programmazione: Compendio C - C++
13 - Programmazione: Compendio C - C++
 
Laboratorio Programmazione: Visibilita' e tipi di dato
Laboratorio Programmazione: Visibilita' e tipi di datoLaboratorio Programmazione: Visibilita' e tipi di dato
Laboratorio Programmazione: Visibilita' e tipi di dato
 
Corso c++
Corso c++Corso c++
Corso c++
 
Caratteristiche del linguaggio c
Caratteristiche del linguaggio cCaratteristiche del linguaggio c
Caratteristiche del linguaggio c
 
Sistemi Operativi: Il kernel linux - Lezione 06
Sistemi Operativi: Il kernel linux - Lezione 06Sistemi Operativi: Il kernel linux - Lezione 06
Sistemi Operativi: Il kernel linux - Lezione 06
 
Le basi di Pytthon 3 - Fondamenti n.1
Le basi di Pytthon 3 - Fondamenti n.1Le basi di Pytthon 3 - Fondamenti n.1
Le basi di Pytthon 3 - Fondamenti n.1
 
Inferno Limbo Italian
Inferno Limbo ItalianInferno Limbo Italian
Inferno Limbo Italian
 
2 Linux Comandi Essenziali
2 Linux Comandi Essenziali2 Linux Comandi Essenziali
2 Linux Comandi Essenziali
 
Linux@Unina
Linux@UninaLinux@Unina
Linux@Unina
 
Lezione 11 (26 marzo 2012)
Lezione 11 (26 marzo 2012)Lezione 11 (26 marzo 2012)
Lezione 11 (26 marzo 2012)
 
Modulo 1 - Lezione 1
Modulo 1 - Lezione 1Modulo 1 - Lezione 1
Modulo 1 - Lezione 1
 
Pycrashcourse
PycrashcoursePycrashcourse
Pycrashcourse
 
Corso java base
Corso java baseCorso java base
Corso java base
 
Pycrashcourse3.1
Pycrashcourse3.1Pycrashcourse3.1
Pycrashcourse3.1
 
Bash intro
Bash introBash intro
Bash intro
 
Lezione 6 (12 marzo 2012)
Lezione 6 (12 marzo 2012)Lezione 6 (12 marzo 2012)
Lezione 6 (12 marzo 2012)
 
7 Sottoprogrammi
7   Sottoprogrammi7   Sottoprogrammi
7 Sottoprogrammi
 
T3 esempio runtime
T3 esempio runtimeT3 esempio runtime
T3 esempio runtime
 
Vogliamo programmatori stupidi e pigri!
Vogliamo programmatori stupidi e pigri!Vogliamo programmatori stupidi e pigri!
Vogliamo programmatori stupidi e pigri!
 
Presentazione Oz - Mozart
Presentazione Oz - MozartPresentazione Oz - Mozart
Presentazione Oz - Mozart
 

Mehr von Majong DevJfu

9 - Architetture Software - SOA Cloud
9 - Architetture Software - SOA Cloud9 - Architetture Software - SOA Cloud
9 - Architetture Software - SOA Cloud
Majong DevJfu
 
8 - Architetture Software - Architecture centric processes
8 - Architetture Software - Architecture centric processes8 - Architetture Software - Architecture centric processes
8 - Architetture Software - Architecture centric processes
Majong DevJfu
 
7 - Architetture Software - Software product line
7 - Architetture Software - Software product line7 - Architetture Software - Software product line
7 - Architetture Software - Software product line
Majong DevJfu
 
6 - Architetture Software - Model transformation
6 - Architetture Software - Model transformation6 - Architetture Software - Model transformation
6 - Architetture Software - Model transformation
Majong DevJfu
 
5 - Architetture Software - Metamodelling and the Model Driven Architecture
5 - Architetture Software - Metamodelling and the Model Driven Architecture5 - Architetture Software - Metamodelling and the Model Driven Architecture
5 - Architetture Software - Metamodelling and the Model Driven Architecture
Majong DevJfu
 
4 - Architetture Software - Architecture Portfolio
4 - Architetture Software - Architecture Portfolio4 - Architetture Software - Architecture Portfolio
4 - Architetture Software - Architecture Portfolio
Majong DevJfu
 
3 - Architetture Software - Architectural styles
3 - Architetture Software - Architectural styles3 - Architetture Software - Architectural styles
3 - Architetture Software - Architectural styles
Majong DevJfu
 
2 - Architetture Software - Software architecture
2 - Architetture Software - Software architecture2 - Architetture Software - Software architecture
2 - Architetture Software - Software architecture
Majong DevJfu
 
1 - Architetture Software - Software as a product
1 - Architetture Software - Software as a product1 - Architetture Software - Software as a product
1 - Architetture Software - Software as a product
Majong DevJfu
 
10 - Architetture Software - More architectural styles
10 - Architetture Software - More architectural styles10 - Architetture Software - More architectural styles
10 - Architetture Software - More architectural styles
Majong DevJfu
 

Mehr von Majong DevJfu (20)

9 - Architetture Software - SOA Cloud
9 - Architetture Software - SOA Cloud9 - Architetture Software - SOA Cloud
9 - Architetture Software - SOA Cloud
 
8 - Architetture Software - Architecture centric processes
8 - Architetture Software - Architecture centric processes8 - Architetture Software - Architecture centric processes
8 - Architetture Software - Architecture centric processes
 
7 - Architetture Software - Software product line
7 - Architetture Software - Software product line7 - Architetture Software - Software product line
7 - Architetture Software - Software product line
 
6 - Architetture Software - Model transformation
6 - Architetture Software - Model transformation6 - Architetture Software - Model transformation
6 - Architetture Software - Model transformation
 
5 - Architetture Software - Metamodelling and the Model Driven Architecture
5 - Architetture Software - Metamodelling and the Model Driven Architecture5 - Architetture Software - Metamodelling and the Model Driven Architecture
5 - Architetture Software - Metamodelling and the Model Driven Architecture
 
4 - Architetture Software - Architecture Portfolio
4 - Architetture Software - Architecture Portfolio4 - Architetture Software - Architecture Portfolio
4 - Architetture Software - Architecture Portfolio
 
3 - Architetture Software - Architectural styles
3 - Architetture Software - Architectural styles3 - Architetture Software - Architectural styles
3 - Architetture Software - Architectural styles
 
2 - Architetture Software - Software architecture
2 - Architetture Software - Software architecture2 - Architetture Software - Software architecture
2 - Architetture Software - Software architecture
 
1 - Architetture Software - Software as a product
1 - Architetture Software - Software as a product1 - Architetture Software - Software as a product
1 - Architetture Software - Software as a product
 
10 - Architetture Software - More architectural styles
10 - Architetture Software - More architectural styles10 - Architetture Software - More architectural styles
10 - Architetture Software - More architectural styles
 
Uml3
Uml3Uml3
Uml3
 
Uml2
Uml2Uml2
Uml2
 
6
66
6
 
5
55
5
 
4 (uml basic)
4 (uml basic)4 (uml basic)
4 (uml basic)
 
3
33
3
 
2
22
2
 
1
11
1
 
Tmd template-sand
Tmd template-sandTmd template-sand
Tmd template-sand
 
26 standards
26 standards26 standards
26 standards
 

14 - Programmazione: Stream e File

  • 2. Input streams 1/2 stream: sequenza di caratteri  istream: meccanismo per convertire  sequenze di caratteri in valori di diverso tipo standard istream: cin  tipicamente associato al terminale da cui è  fatto partire il programma appartiene al namespace std  E' questo uno dei motivi per cui abbiamo  aggiunto nei nostri programmi la direttiva using namespace std ; 2
  • 3. Input streams 2/2 Come si leggono valori?  Operatore >> (leggi, estrai)  Input formattato ...  3
  • 4. Input formattato Le cifre sono convertite in numeri se si  leggono interi o reali I caratteri speciali sono saltati se si  leggono singoli caratteri Ad esempio è saltato il newline 'n'  Gli spazi bianchi (spazio, tab, newline,  form-feed, ...) sono saltati se si leggono stringhe 4
  • 5. Stream state Ciascun (i/o)stream ha un proprio  stato Insieme di flag (valori booleani)  Errori e condizioni non standard sono  gestiti assegnando o controllando in modo appropriato lo stato 5
  • 6. End Of File (EOF) (EOF) Classica condizione che impedisce di  effettuare ulteriori operazioni: leggere la marca EOF da uno stream di input Nel caso in cui si stia effettivamente  leggendo un file attraverso l'istream, vuol dire che si è raggiunta la fine del file Nel caso di input da un terminale  UNIX, l'EOF è generato se si preme Ctrl-D (su riga vuota) 6
  • 7. Espressioni con >> cin e cin>>..., oppure !cin e  !(cin>>...) sono espressioni Es.:, cin>>dim è una espressione che ha  un suo valore di ritorno Ovviamente come sappiamo la valutazione  di tale espressione comporta la lettura da cin mediante l'operatore >>, e quindi l'assegnamento alla variabile dim di un opportuno valore in base al contenuto (e come vedremo allo stato) del cin 7
  • 8. Controllo stato istream Le precedenti espressioni si possono  utilizzare dove è atteso un valore booleano, ed in tal caso il significato del loro valore è il seguente Vero: la prossima operazione può aver  successo perché lo stream è in stato buono Falso: la prossima operazione fallirà perché  lo stream è in stato non-buono  Il motivo per lo stato non-buono è che l'ultima operazione è fallita: formato errato dell'input oppure incontrato EOF 8
  • 9. Stato istream Una volta in stato non-buono, lo  stream ci rimane finché i flag non sono esplicitamente resettati Semplice istruzione per resettare lo  stato dello stream: cin.clear() ; Operazioni di input su stream in stato  non-buono sono operazioni nulle Bisogna resettare prima di effettuare  la prossima operazione di input 9
  • 10. Esercizio Scrivere un programma che, dopo aver  letto da stdin una sequenza di numeri interi, stampi la somma dei valori letti La lunghezza della sequenza non è  nota a priori, nè comunicata prima di iniziare ad immettere i numeri Soluzione nella prossima slide  10
  • 11. Esercizio #include <iostream> using namespace std ; main() { int i, somma = 0 ; while (cin>>i) somma += i ; cout<<quot;Somma: quot;<<somma<<endl ; // se volessi continuare ad usare // il cin, dovrei prima invocare // cin.clear() } 11
  • 12. Operazioni di input nulle Come già detto, quando una operazione  di input fallisce, è una vera e propria operazione nulla: nessun carattere è rimosso dallo  stream di input il valore della variabile di destinazione è  lasciato inalterato Esempio:  int i = 3 ; cin>>i ; // se il cin è in stato di errore, // in i rimane 3 indipendentemen- // te dal contenuto dello stdin 12
  • 13. Output streams ostream: meccanismo per convertire valori  di vario tipo in sequenze di caratteri Output formattato  standard output ostream e standard  error ostream: cout e cerr ostream tipicamente collegati al terminale  da cui è fatto partire il programma appartengono al namespace std  13
  • 14. Operazioni di uscita 1/2 Supponiamo per un momento che all'interno  dell'oggetto cout vi sia del codice che scriva immediatamente su stdout ogni singolo carattere ad esso passato mediante l'operatore << Questo comporterebbe la lettura separata di  ciascuno di tali caratteri da parte della shell da cui abbiamo lanciato il programma La shell a sua volta passerebbe uno ad uno i  i caratteri letti terminale, che si occuperebbe a sua volta di comunicare col sistema operativo per farli apparire (di nuovo uno alla volta) 14
  • 15. Operazioni di uscita 2/2 Ciascuna delle precedenti operazioni su  singolo carattere avrebbe più o meno lo stesso costo se effettuata su un intera stringa Allora perché non cercare di effettuarle  per stringhe di più di un carattere anziché carattere per carattere? Una possibilità sarebbe ad esempio  quella di mandare su stdout una riga alla volta, ossia una stringa che ha un newline come ultimo carattere 15
  • 16. Buffer 1/2 A questo scopo potremmo immaginare  che l'oggetto cout memorizzi temporaneamente i caratteri che gli vengono passati in un proprio array di caratteri, e li scriva effettivamente sullo stdout solo quando quest'array di caratteri arriva a contenere una riga Tutte le precedenti operazioni non  sarebbero più effettuate per ogni singolo carattere, ma una riga alla volta Molto più efficiente  16
  • 17. Buffer 2/2 Tale array di caratteri è un esempio di  buffer Si indica col termine buffer (memoria  tampone) un array di byte utilizzato nelle operazioni di I/O Vi si memorizzano temporaneamente  le informazioni prime di spostarle nella destinazione finale Il motivo principale per l'uso di un  buffer è l'efficienza 17
  • 18. Uscita bufferizzata Le operazioni di uscita con gli stream  sono effettivamente tipicamente bufferizzate Ad esempio il passaggio dei caratteri  da stampare allo stdout non avviene carattere per carattere, bensì i caratteri vengono spediti tutti assieme proprio quando si inserisce il newline 18
  • 19. Buffer e incoerenza dell'uscita Si possono però avere problemi di  incoerenza delle informazioni in uscita Ad esempio se un programma fallisce  dopo una scrittura su cout in cui non si è inserito il newline, i corrispondenti caratteri potrebbero non essere mai passati allo stdout Vederemo a breve un problema simile  con le scritture su file 19
  • 20. Svuotamento del buffer Si può scatenare lo svuotamento del  buffer anche senza l'invio del newline  endl inserisci un newline e svuota il buffer di uscita (la soluzione con il newline che conosciamo già)  flush svuota il buffer di uscita (senza aggiungere alcun carattere) Es.: cout<<quot;Provaquot;<<flush ; 20
  • 21. Due argomenti extra I prossimi due argomenti, ossia  rimuovere i caratteri da stdin e formattare l'output, non saranno argomento d'esame 21
  • 22. Rimuovere caratteri da stdin Si possono rimuovere  incondizionatamente caratteri da un istream con la seguente funzione cin.ignore() ignora, ossia rimuove, il  prossimo carattere da stdin Vediamone l'uso con un esempio  22
  • 23. Soluzione non sicura int main() { int *p ; // attenzione, per ora contiene un valore casuale !!! int dim = -1 ; do { // immissione dimensioni array cout<<quot;Dimensioni array? quot; ; Che succede se si immette cin>>dim ; un carattere anziché una } while (dim < 0) ; cifra? p = new int[dim] ; // allocazione memoria ... } 23
  • 24. Una soluzione sicura int main() { int *p ; // attenzione, per ora contiene un valore casuale !!! int dim = -1 ; do { // immissione dimensioni array cout<<quot;Dimensioni array? quot; ; while(!(cin>>dim)) { Però non cin.clear() ; esce in cin.ignore(); caso di cout<<quot;Devi immettere un numero: quot; ; } EOF! } while (dim < 0) ; La soluzione è lasciata p = new int[dim] ; // allocazione memoria al ... lettore ... } 24
  • 25. Formattazione dell'output Come già detto i seguenti argomenti di  formattazione dell'output non saranno argomento di esame 25
  • 26. Esempio di output formattato What's your name? Paolo Health (in hundredths)? 35 Welcome to GOTA, Paolo. And good luck! Giustificato Lunghezza proporzionale a sinistra agli health points Paolo--------------------------------------------------------------- | Health points: 035/100| ###### | |---------------------------------------------------------------------| 80 colonne (obbligatorio) > 26
  • 27. Formattazione dell'Output La formattazione è controllata da un  insieme di flag e valori interi Semplice interfaccia per assegnare tali  valori: funzioni dedicate e manipolatori 27
  • 28. setprecision cout.setprecision(int n)  Setta il massimo numero di cifre per un numero in virgola mobile l'effettivo output dipende dal formato  (generale, scientifico, fisso) l'effetto è persistente: influenza tutte  le prossime operazioni di uscita, fino alla prossima evetuale chiamata di setprecision 28
  • 29. Manipolatore Operazione che modifica lo stato, da  passare agli operatori di ingresso/uscita allo stesso modo degli oggetti che si da scrivere/leggere Esempi (già visti) di manipolatori che  non prendono argomenti: flush svuota il buffer di uscita  endl inserisci un newline e svuota  il buffer di uscita 29
  • 30. Manipolatori con argom. 1/2 Spesso si vuole riempire con del testo  predefinito un certo spazio su una linea cout<<...<<setw(int n)<<...  Setta il minimo numero di caratteri per la prossima operazione di uscita cout<<...<<setw(...)<<setfill(char c)<<...  Sceglie il carattere in c come carattere di riempimento 30
  • 31. Manipolatori con argom. 2/2 Per usare manipolatori che prendono  argomenti bisogna includere: #include <iomanip> 31
  • 32. Stampa dello stato del gioco #include <iostream> #include <iomanip> using namespace std ; int main() { int punti_salute = 35 ; cout<<left<<setw(80)<<setfill('-')<<quot;Paoloquot;<<endl ; cout<<quot;| Health points: quot;<<right<<setw(3)<<setfill('0')<<punti_salute<<quot;/100 | quot; ; int num_asterischi = punti_salute*51/100 ; cout<<setw(num_asterischi)<<setfill('#')<<quot;quot; ; cout<<setfill(' ') ; cout<<setw(53 - num_asterischi)<<right<<quot; |quot;<<endl ; cout<<setw(80)<<setfill('-')<<quot;quot;<<endl ; return 0 ; } 32
  • 33. Torniamo agli argomenti che  saranno oggetto d'esame ... 33
  • 34. Definizione di nuovi stream cout, cerr, cin sono già pronti all'uso  quando un programma parte Sono creati automaticamente ed  associati allo stdout, stdin e stderr del programma Però possiamo anche creare i nostri  stream  Alla creazione di uno stream dobbiamo specificare l'oggetto a cui è associato  Un tipico oggetto a cui associare uno stream è un file 34
  • 35. fstream I seguenti tipi di stream sono da  associare ai file, e sono supportati direttamente dalla libreria standard del C++ (non da quella del C) ifstream: file stream di ingresso (lettura)  ofstream: file stream di uscita (scrittura)  fstream: file stream di ingresso/uscita  Presentati in <[i | o]fstream> o in  <fstream> (tutti e tre) 35
  • 36. Modello di file Un file è visto come una sequenza di  caratteri (byte) che, come vedremo, potrà essere letta attraverso un ifstream (o uno fstream opportunamente inizializzato) o modificata attraverso un ofstream (o di nuovo uno fstream opportunamente inizializzato) 36
  • 37. Associazione a file Un (i|o)fstream viene associato ad un file  mediante un'operazione chiamata apertura del file Da quel momento in poi tutte le  operazioni di ingresso/uscita fatte sullo stream si tradurranno in identiche operazioni sul contenuto del file E' il sistema operativo che si occuperà di  tutti i dettagli (che variano da sistema a sistema) necessari per eseguire le operazioni sulla macchina reale 37
  • 38. Associazione a file Come nome del file si può indicare tanto un  percorso assoluto che un percorso relativo Esempio di percorso assoluto:  /home/paolo/dati.txt File di nome dati.txt nella cartella /home/paolo Esempi di percorsi relativi (il file è cercato  nella cartella corrente): paolo/dati.txt File di nome dati.txt nella sottocartella paolo della cartella corrente dati.txt File di nome dati.txt nella cartella corrente 38
  • 39. Associazione a file E' possibile aprire più di un file  contemporaneamente L'apertura di un file può fallire per  diversi motivi Ad esempio se si tenta di aprire in  lettura un file inesistente E' opportuno controllare sempre l'esito  dell'operazione di apertura prima di utilizzare un (i|o)fstream 39
  • 40. Apertura file 1/3 Un file è aperto in input definendo un  oggetto di tipo ifstream e passando il nome del file come argomento ifstream f(“nome_file”) ; if (!f) cerr<<”l'apertura è fallitan” ; Un file è aperto in output definendo un  oggetto di tipo ofstream e passando il nome del file come argomento ofstream f(“nome_file”) ; if (!f) cerr<<”l'apertura è fallitan” ; 40
  • 41. Apertura file 2/3 Un file può essere aperto per l'ingresso  e/o l'uscita definendo un oggetto di tipo fstream e passando il nome del file come argomento Deve essere fornito un secondo  argomento openmode ios_base::in oppure ios_base::out  Se non esiste, un file aperto in scrittura  viene creato, altrimenti viene troncato a lunghezza 0 41
  • 42. Apertura file 3/3 Esempi:  // file aperto in ingresso fstream f(“nome_file”, ios_base::in) ; if (!f) cerr<<”apertura fallitan” ; // file aperto in uscita fstream f2(“nome_file”, ios_base::out) ; if (!f) cerr<<”apertura fallitan” ; 42
  • 43. Gerarchia degli stream ios_base deriva da ios ostream istream ofstream ifstream iostream fstream 43
  • 44. Conseguenza immediata Si possono usare tutti gli operatori, i flag  di stato, e le funzioni di utilità per la formattazione viste per gli stream di ingresso/uscita standard Quindi si può quindi controllare lo stato di  un oggetto (i|o)fstream f usando il suo identificatore in una espressione condizionale Esempio: if (!f) cerr<<”La precedente operazione è” <<”fallita”<<endl ; 44
  • 45. Informazioni aggiuntive Come visto negli esempi, con oggetti di  tipo ifstream, ofstream o fstream si controlla il successo o meno dell'apertura controllando lo stato Più modi possono essere combinati  mediante l'operatore | in: input, out: output, app: append (si  continua a scrivere a partire dal fondo) ofstream f(“nome_file”, ios_base::app) ; 45
  • 46. Bufferizzazione uscita Per gli stessi motivi di efficienza visti per  gli ostream collegati allo stdout, anche le operazioni di uscita su ofstream (oppure fstream inizializzati in scrittura) sono tipicamente bufferizzate Quindi, a meno di passare ad esempio i  manipolatori endl e/o flush non è garantito che una certa scrittura sia immediatamente effettuata sul file associato 46
  • 47. Chiusura file Un file può essere chiuso invocando la  funzione close() sullo stream ad esso associato Es.: f.close() ; Un file è comunque chiuso implicitamente  alla distruzione dello stream associato La chiusura (esplicita o implicita) di un file è  importante perché solo all'atto della chiusura ne è garantito l'effettivo aggiornamento (svuotamento dei buffer) 47
  • 48. open Si può anche aprire un file invocando la  funzione open su uno stream non ancora associato ad alcun file (non inizializzato o deassociato mediante close) Per brevità non vedremo la open in queste  lezioni 48
  • 49. Esercizio file/file.cc  49
  • 50. Domanda Siete riusciti a risolvere l'esercizio in  modo completo? Probabilmente no, perché l'operatore  >> ha saltato i caratteri 'n' Vedremo a breve la soluzione mediante  I/O non formattato 50
  • 51. Esercizio Leggere da un file di testo dati.txt una  sequenza di numeri interi di al più 100 elementi, finché non si trova il primo elemento uguale a 0. Memorizzare tutti i numeri letti in un vettore. 51
  • 52. Soluzione main() { int vett[100] ; ifstream f(quot;dati.txtquot;); if (!f) cerr<<quot;Errore di apertura filenquot;; else for (int i = 0 ; i < 100 && f>>vett[i] && vett[i] != 0 ; i++) ; } 52
  • 53. Esercizi (senza soluzione) ESERCIZIO 1: Leggere da un file di testo dati.txt una  sequenza di numeri interi terminata da 0. Memorizzare in un vettore tutti i numeri negativi. ESERCIZIO 2: Leggere da un file di testo dati.txt una  sequenza di numeri interi terminata da 0. Memorizzare in un vettore tutti i numeri compresi tra –30 e +30 escluso lo 0. Ordinare il vettore in modo crescente e stampare tutti i numeri positivi. ESERCIZIO 3: Leggere da un file di testo dati.txt una  sequenza di caratteri terminata da *. Memorizzare in un vettore tutti i caratteri alfabetici. 53
  • 54. Esercizio Scrivere in un file di testo valori_pos.txt tutti  i numeri strettamente positivi di un vettore contenente N valori interi, con N definito a tempo di scrittura del programma. Alla fine, inserire il valore -1 come terminatore. 54
  • 55. Soluzione main() { const int N = 10 ; int vett[N] ; ofstream f(“dati.txt”); if (!f) cerr<<”Errore di apertura filenquot;; else { for (int i=0; i<N; i++) if (vett[i]>0) f<<vett[i]; f<<-1 ; } } 55
  • 56. Esercizi (senza soluzione) ESERCIZIO 1: Scrivere in un file di testo “carat.txt”  tutti i caratteri di una stringa letta da input. Terminare la sequenza di caratteri del file con *. ESERCIZIO 2: Leggere da un file di testo  “dati_inp.txt” una sequenza di numeri interi terminata da 0, e copiare in un vettore solo gli elementi positivi. Copiare tutti i valori del vettore compresi fra 10 e 100 in un file di testo “dati_out.txt”. ESERCIZIO 3: Come l’esercizio 4.c. In più, stampare  su schermo il contenuto del file “dati_out.txt”. 56
  • 57. I/O formattato Gli operatori di ingresso/uscita visti  finora, ossia >> e <<, interpretano il contenuto di uno stream come una sequenza di caratteri Traducono quindi valori in caratteri e  viceversa Le operazioni di ingresso/uscita in cui  uno stream è visto come una sequenza di caratteri si definiscono operazioni di ingresso/uscita formattate 57
  • 58. I/O non formattato Esistono anche operazioni di ingresso/  uscita non formattate Vedono lo stream come una mera  sequenza di byte e non effettuano alcuna trasformazione di alcun tipo Trasferiscono semplicemente sequenze  di byte da uno stream ad un array di byte (o un singolo byte), o da un array di byte (o un singolo byte) ad uno stream 58
  • 59. Funzioni membro Le funzioni di lettura e scrittura non  formattate che vedremo sono delle funzioni membro Per utilizzarle bisogna usare la notazione a  punto Se f è un istream, allora per usare ad  esempio una funzione membro fun(char &), bisogna scrivere f.fun(c) ; Es.: char c ; cin.fun(c) ; 59
  • 60. Buffer ed I/O non formattato Come già visto, un buffer è un array  di byte utilizzato nelle operazioni di I/O Il tipo char ha esattamente la  dimensione di un byte Per questo motivo il tipo char è  utilizzato anche per memorizzare byte nelle letture e le scritture non formattate 60
  • 61. Input non formattato Gli istream dispongono delle seguenti  funzioni membro per input non formattato: get() get(char &) get(char *buffer, int n, char delimitatore='n') read(char *buffer, int n) gcount() 61
  • 62. get() Ritorna, su un int, il valore del  prossimo byte nello stream di ingresso a cui è applicata Ritorna il valore EOF in caso di fine input  Esempio:  main() { int i = cin.get() ; ... } 62
  • 63. get(char &c) 1/2 Preleva un byte e lo assegna alla  variabile passata come argomento La variabile è lasciata inalterata in caso di  fine input Esempio:  main() { char c ; cin.get(c) ; ... } 63
  • 64. get(char &c) 2/2 Per semplicità, diciamo che ritorna lo istream a  cui è applicata Quindi si può usare allo stesso modo di uno  istream in espressioni che si aspettano un booleano Esempio:  main() { char c ; while(cin.get(c)) ... } 64
  • 65. Esercizio file/file_conta_linee.cc  65
  • 66. Lettura in un buffer get(char *buffer, int n, char delimitatore='n') Legge byte dallo stream di ingresso e li  trasferisce in buffer aggiungendo il carattere '0' finale La lettura va avanti finché non si sono  letti n byte oppure non è stato incontrato il delimitatore Se il terzo argomento non è passato, si usa  come delimitatore il codice del carattere 'n' 66
  • 67. Esempio di lettura in un buffer main() { char buf[100] ; // lettura di al più 50 byte, a meno // non si incontri il codice del // carattere '-' // in fondo è inserito '0' cin.get(buf, 50, '-') ; ... } 67
  • 68. Lettura in un buffer 2 read(char *buffer, int n) Legge n byte e li memorizza nell'array  buffer Non è previsto alcun delimitatore, né  aggiunto alcun terminatore gcount() Ritorna il numero di caratteri letti  nell'ultima operazione di lettura 68
  • 69. Scrittura non formattata put(char c) Trasferisce un byte (il contenuto di c)  sullo stream di uscita write(const char *buffer, int n) Trasferisce i primi n byte di buffer  sullo stream di uscita Non è inserito alcun terminatore  69
  • 70. File di testo e file binari 1/2 Se si effettuano solo letture e scritture  formattate su uno stream, si dice che lo si sta usando in modo testo In maniera simile, come già sappiamo,  un file i cui byte sono da interpretarsi come codici di caratteri si definisce un file di testo Altrimenti si usa tipicamente la  denominazione file binario 70
  • 71. File di testo e file binari 2/2 Per lavorare con file binari sono  estremamente comode le letture/scritture non formattate, perché permettono appunto di ragionare in termini di pure sequenze di byte Ricordare sempre però che un file  rimane comunque solo una sequenza di byte, ed il fatto che sia un file di testo o un file binario è solo una questione di come è da interpretare tale sequenza di byte 71
  • 72. Puntatori ed array Estendiamo le nostre conoscenze  Come sappiamo il tipo puntatore  <tipo> * memorizza indirizzi Come mai possiamo passare un array  come argomento attuale nella posizione corrispondente ad un parametro formale di tipo <tipo> * ? Perché passare il nome di un array è  equivalente a passare l'indirizzo del primo elemento dell'array 72
  • 73. Esempio con tipo char void fun(const char *a) { ofstream f(quot;nomequot;) ; // trasferiamo due elementi, // ossia due byte dell'array a f.write(a, 2) ; } main() { char b[3] = {14, 31, 66} ; fun(b) ; // passo l'indirizzo di b } 73
  • 74. Oggetti e puntatori Il tipo char * memorizza indirizzi  Possiamo scriverci dentro l'indirizzo di  qualsiasi oggetto, dinamico o non dinamico, non solo quindi di un array dinamico In particolare, possiamo anche scriverci  dentro l'indirizzo di oggetti di tipo diverso da array di caratteri 74
  • 75. Trasferimento oggetti generici Le funzioni di ingresso/uscita non formattate  si aspettano però solo array di caratteri Per usare tali funzioni dobbiamo perciò  convertire il tipo dell'indirizzo di un oggetto diverso da un array di caratteri mediante: reinterpret_cast<char *>(<indirizzo>) Si può anche aggiungere il const  Proviamo a vedere il significato logico di  tale conversione 75
  • 76. Oggetti in memoria 1/3 Consideriamo ad esempio un array di interi  di 3 elementi: Supponendo che ogni elemento occupi 4  byte, l'array in memoria sarà fatto così: Si tratta di una tipica sequenza di byte  76
  • 77. Oggetti in memoria 2/3 Tale sequenza di byte ha qualche differenza  intrinseca rispetto ad una qualsiasi altra sequenza di byte di pari lunghezza? 77
  • 78. Oggetti in memoria 3/3 No  Prendendo in prestito dal C/C++ il termine  array, possiamo dire che una sequenza di byte non è altro che un array di byte Ma sappiamo che un byte può essere  rappresentato esattamente su di char Quindi, qualsiasi sequenza di byte può  essere rappresentata con array di char 78
  • 79. Significato conversione Pertanto  reinterpret_cast<char *>(<indirizzo_oggetto>) Da un punto di vista logico vuol dire:  “Interpreta come una sequenza di byte il contenuto della memoria a partire dall'indirizzo dell'oggetto” Rimane il problema di sapere la lunghezza di  tale sequenza di byte Non solo, in generale potremmo voler  trasferire una sequenza di byte, ossia un array di caratteri, relativa solo ad una porzione dell'intero oggetto 79
  • 80. Dimensioni in byte 1/2 Dato un generico array di elementi di  qualche tipo, possiamo calcolare la lunghezza della sequenza di byte occupati da un certo numero di elementi dell'array nel seguente modo Utilizziamo l'operatore sizeof per  conoscere le dimensioni di ogni elemento, e moltiplichiamo per il numero di elementi 80
  • 81. Dimensioni in byte 2/2 Consideriamo di nuovo un array di interi di 3  elementi e supponiamo che'operatore sizeof ci dica che ogni elemento occupa 4 byte: 4 byte 4 byte 4 byte L'array in memoria occupa 4x3=12 byte  4 byte 4 byte 4 byte 81
  • 82. Scrittura intero array void scrivi_array_su_file(const int *a) { ofstream f(quot;file_destinazionequot;) ; f.write( reinterpret_cast<const char *>(a), sizeof(int) * 3 ); } main() { int b[3] = {1, 2, 7} ; scrivi_array_su_file(b) ; } 82
  • 83. Scrittura su file binari Cosa abbiamo fatto?  Abbiamo scritto nel file di nome  file_destinazione la rappresentazione in memoria, byte per byte, dell'array di interi b file_destinazione sarà certamente un  file binario Esercizio: file/scrivi_leggi_array.cc  83
  • 84. Domanda Potevamo scrivere gli elementi uno  alla volta nel file binario? 84
  • 85. Bufferizzazione Sì, ma sarebbe stato molto inefficiente  Abbiamo dovuto invece scrivere gli  elementi uno alla volta nel caso del file di testo Ma l'efficienza non si è persa, perché,  come già detto, ci ha pensato l'operatore di uscita a bufferizzare le informazioni al posto nostro 85
  • 86. Passaggio indirizzo Come abbiamo visto, il nome di un  array in una espressione denota l'indirizzo di un array Pertanto passare un array come  parametro formale equivale a passare l'indirizzo dell'array E se volessimo passare ad una delle  funzioni di ingresso/uscita l'indirizzo di un oggetto diverso da un array? Ad esempio un singolo intero, o un  singolo oggetto di tipo struttura? 86
  • 87. Operatore indirizzo In questo caso dovremmo utilizzare  l'operatore indirizzo & Si tratta di un operatore unario prefisso  Sintassi  & <nome_oggetto> Semantica: ritorna l'indirizzo  dell'oggetto passato per argomento Come sarà fatto l'oggetto in memoria?  87
  • 88. Generico oggetto in memoria Consideriamo un generico oggetto, per  esempio di tipo strutturato Se l'oggetto occupa ad esempio 8 byte,  allora in memoria si avrà la seguente sequenza di byte a partire dall'indirizzo dell'oggetto: Come già sappiamo, è una tipica sequenza  di byte, rappresentabile mediante un array di caratteri 88
  • 89. Esempio con struct 1/2 main() { struct part {char nome[10]; int tempo} mario ; strcpy(mario.nome, quot;Marioquot;) ; mario.tempo = 30 ; char * const p = reinterpret_cast<char *>(& mario) ; } Use dell'operatore & per ritornare l'indirizzo dell'oggetto 89
  • 90. Esempio con struct 2/2 In p è finito l'indirizzo in memoria  dell'oggetto struttura mario La conversione si è resa necessaria perché  p punta ad oggetti di tipo diverso Come facciamo ad accedere solo  all'effettivo numero di byte occupati da mario? Utilizziamo l'operatore sizeof  90
  • 91. Scrittura su file binari 1/2 main() { struct part {char nome[10]; int tempo} mario ; strcpy(mario.nome, quot;Marioquot;) ; mario.tempo = 30 ; char * const p = reinterpret_cast<char *>(& mario) ; ofstream f(quot;dati.datquot;) ; f.write(p, sizeof(mario)) ; } 91
  • 92. Scrittura su file binari 2/2 Cosa abbiamo fatto?  Abbiamo scritto nel file dati.dat la  rappresentazione in memoria, byte per byte, dell'oggetto mario dati.dat è certamente un file binario  92
  • 93. Lettura da file binari Come facciamo a rimettere in memoria le  informazioni salvate nel file? file_binario.cc  Prima di andare avanti è opportuno  osservare che quanto fatto con un oggetto di tipo struct è solo un altro esempio di lettura/scrittura da/su file binario Si potevano fare esempi con matrici o  array di oggetti struttura, e così via ... 93
  • 94. Accesso sequenziale e casuale Uno stream è definito ad accesso  sequenziale se ogni operazione interessa caselle dello stream consecutive a quelle dell'operazione precedente Uno stream è definito ad accesso  casuale se per una operazione può essere scelta arbitrariamente la posizione della prima casella coinvolta Per cin, cout e cerr è definito solo  l'accesso sequenziale 94
  • 95. Accesso casuale ai file La casella a partire dalla quale avverrà la  prossima operazione è data da un contatore che parte da 0 (prima casella) Il suo contenuto può essere modificato  con le funzioni membro seekg(nuovo_valore) per file in ingresso (la g sta per get) seekp(nuovo_valore) per file in uscita (la p sta per put) 95
  • 96. Accesso casuale ai file Le due funzioni possono anche essere  invocate con due argomenti seekg(offset, origine) seekp(offset, origine) L'origine può essere:  ios::beg offset indica il numero di posizioni a partire dalla casella 0 (equivalente a non passare un secondo argomento) ios::end offset indica il numero di posizioni a partire dall'ultima casella (muovendosi all'indietro) 96
  • 97. Lettura della posizione Per gli ifstream è definita la funzione  tellg() Ritorna il valore corrente del contatore Per gli ofstream è definita la funzione  tellp() Ritorna il valore corrente del contatore 97
  • 98. Passaggio di stream 1/2 Uno stream può essere passato per  riferimento ad una funzione cin può essere passato come parametro attuale in corrispondenza di un parametro formale di tipo istream & cout può essere passato come parametro attuale in corrispondenza di un parametro formale di tipocome ostream & 98
  • 99. Passaggio di stream 2/2 Gli (i|o)fstream possono essere passati per  riferimento dove sono attesi gli (i|o)stream un ifstream può essere passato come parametro attuale in corrispondenza di un parametro formale di tipo istream & un ofstream può essere passato come parametro attuale in corrispondenza di un parametro formale di tipo ostream & 99
  • 100. Esempio void stampa(ostream &o) { o<<quot;Stringaquot;<<endl ; } void leggi(istream &i) { char s[100] ; i>>s ; cout<<s<<endl ; } main() { stampa(cout) ; // stampa su stdout ofstream f(quot;nome_file.txtquot;) ; stampa(f) ; // scrive nel file leggi(cin) ; // legge da stdin ifstream f2(quot;nome_file.txtquot;) ; leggi(f2) ; // legge dal file } 100
  • 101. Esercizio Dato un file binario in cui sono  memorizzati oggetti di tipo struct persona { char codice[7]; char Nome[20]; char Cognome[20]; int Reddito; int Aliquota; }; ed assumendo che ogni persona abbia un codice univoco ... 101
  • 102. Esercizio Scrivere una funzione che prenda in ingresso  un oggetto P di tipo persona per riferimento, ed un istream che contiene la rappresentazione binaria di una sequenza di oggetti di tipo persona. La funzione cerca nello istream un oggetto con lo stesso valore del campo codice dell'oggetto P e, se trovato, riempie i restanti campi dell'oggetto P con i valori dei corrispondenti campi dell'oggetto trovato nel file. La funzione ritorna true in caso di successo, ossia se l'oggetto è stato trovato, false altrimenti 102
  • 103. Soluzione bool ricerca_file(persona &P, istream &f) { bool trovato=false; while (true) { persona buf[1] ; f.read(reinterpret_cast<char *>(buf), sizeof(persona)) ; if (f.gcount() <= 0) break ; if (strcmp(buf[0].Nome, P.Nome) == 0) { P = buf[0] ; trovato = true ; break ; } } return trovato; } 103
  • 104. Osservazioni finali 1/2 I file sono una delle strutture dati  fondamentali per la soluzione di problemi reali Infatti nella maggior parte delle applicazioni  reali i dati non si leggono (solamente) da input e non si stampano (solamente) su terminale, ma si leggono da file e si salvano su file 104
  • 105. Osservazioni finali 2/2 Spesso si rende necessario gestire grandi  quantità di dati su supporti di memoria secondaria in modo molto efficiente Gli informatici vedranno come negli  insegnamenti di “BASI DI DATI” Ricordare infine che la gestione dei file sarà  sempre parte della prova di programmazione 105