Ripasso
Settimana scorsa abbiamo parlato di stringhe e caratteri, vi avevo proposto un buon numero di esercizi quindi proviamo a rivedere le soluzioni.
Lettura e scrittura da file
Oggi impariamo a leggere e scrivere dati da e su file di testo. I file sono il mezzo che abbiamo per conservare dell'informazione sul computer in maniera semi-permanente. Le nostre variabili vivono solo in memoria e spariscono una volta fermata l'esecuzione del programma, quindi se é necessario mantenere informazione nel tempo siamo costretti a scriverla da qualche parte.
Come vedremo queste operazioni su file sono molto simili a quello che abbiamo giá imparato per leggere e scrivere da e su terminale.
Aprire un file in lettura
Il pacchetto os mette a disposizione un modo per aprire un file mediante la
funzione os.Open(name string) (*File, error), per ora ignorate quel
*File e pensate solamente che si tratta del tipo che descrive un file. Se
avremo tempo proveremo a parlare di come creare nuovi tipi in Go, ma non é
questo il momento. Ogni file che viene aperto deve TASSATIVAMENTE essere
chiuso prima della fine del programma, per farlo si usa questa sintassi:
f, _ := os.Open("nome_file.txt") // Apro il file 'nome_file.txt'
// Leggo dati dal file nominato 'nome_file.txt'
f.Close() // Chiudo il file
Creare un file
Il pacchetto os mette a disposizione la funzione
os.Create(name string) (*File, error) per creare un nuovo file in modalità
lettura/scrittura.
ATTENZIONE Se il file esiste giá i contenuti verranno sovrascritti.
f, _ := os.Create("nuovo.txt") // Creo il file 'nuovo.txt'
// Leggo o scrivo dati da/su 'nuovo.txt'
f.Close() // Chiudo il file
Leggere da file aperto
Una volta aperto un file con os.Open per leggere dati si usa la funzione
fmt.Fscan in questo modo:
f, _ := os.Open("nome_file.txt") // Apro il file 'nome_file.txt'
var s string
fmt.Fscan(f, &s) // Leggo una stringa dal file
fmt.Println(s)
f.Close()
Scrivere su file aperto
Una volta aperto un file in lettura con os.Create si possono scrivere una
quantità arbitraria di dati:
f, _ := os.Create("nuovo.txt") // Apro il file 'nuovo.txt'
fmt.Fprintln(f, "Questa riga andrà nel file") // Scrivo sul file
f.Close() // Chiudo il file
Aggiungere ad un file esistente
Uno dei problemi della funzione os.Create è che file già esistenti vengono
troncati e sovrascritti, per evitare questo si può usare la funzione
os.OpenFile(name string, flag int, perm FileMode) (*File, error) che è la
generalizzazione delle altre due. Il funzionamento è un pochino più complicato,
e permette maggiore controllo. A noi interessa soltanto aggiungere ad un file
esistente:
f, _ := os.CreateFile("esistente.txt", O_APPEND, 0666)
fmt.Fprintln("Aggiunto alla fine")
f.Close()
Il pacchetto fmt
Molte delle funzioni del pacchetto fmt hanno degli analoghi che
interagiscono con file, generalmente queste funzioni si riconoscono perchè il
loro nome é identico a quelle che già conoscete ma con una 'F' come prefisso.
Ad esempio fmt.Fprint, fmt.Fscan... tutte queste funzioni accettano
come primo argomento un file.
Dei file importanti
L'input e l'output del terminale su sistemi Unix (progenitore di Linux) sono
semplicemente dei file, in particolare dei file chiamati standard input e
standard output. Le funzioni che agiscono su file possono agire anche su
questi due file particolari che sono forniti dal pacchetto os nelle
variabili os.Stdin e os.Stdout. os.Stdin è aperto in lettura,
mentre os.Stdout è aperto in sola scrittura.
Lo standard error
Un terzo file molto importante, inventato su sistemi Unix è il cosiddetto
standard error, questo file viene usato esclusivamente per stampare
errori. Il pacchetto os mette ad disposizione questo file, aperto in
modalità di scrittura, nella variabile os.Stderr.
Note per la prossima lezione
Al momento le nostre capacità di lettura sono piuttosto limitate, ma più avanti impareremo come gestire meglio l'input: come leggere un file riga per riga, parola per parola ecc. Per ora accontentiamoci
Esercizi
Esercizio 0 - Cat
Problema: Scrivere un programma cat.go che riproduce l'analogo programma
UNIX (chiamato cat). Lo scopo di questo programma è stampare il contenuto
di file.
Nota: Il funzionamento di cat è il seguente:
cat file1 file2
contenuto di file1
contenuto di file2
siccome noi non abbiamo ancora imparato a trattare gli argomenti dati al programma, lo modificheremo in questo modo:
$ cat
Nomi dei file: **file1 file2**
contenuto di file1
contenuto di file2
Esercizio 1 - Wc
Problema: Scrivere un programma wc.go che riproduce l'analogo programma
UNIX (chiamato wc). Lo scopo di questo programma è contare il numero di
parole in un file.
Nota: Un problema analogo a quello di cat si ripropone qui. Leggi la nota
all'esercizio 0
Esempi di esecuzione:
$ wc
Nome di file: file1 file2
file1: 40 parole
file2: 20 parole
Totale: 60 parole
Esercizio 2 - Database 2
Problema: Scrivere un programma database2.go che amplii il funzionamento
del programma analogo visto nella lezione precedente. Dato un file db.txt
in cui ogni riga ha il seguente formato:
nome;cognome;email;ultimo voto
stampare le informazioni contenute nel file nel formato discusso alla lezione precedente.
Esercizio 3 - Ricerca di parole
Problema: Scrivere un programma cerca_parole.go che legge in input il
nome di un file e una chiave di ricerca e stampi true oppure false se
la chiave è presente nel file.
Facoltativo: Provate ad implementare la ricerca in modo da tenere traccia della riga in cui la parola è stata trovata. Il programma dovrà quindi stampare il numero della riga a cui è stata trovata la parola, oppure -1 se la chiave non è presente nel file.
Esempi di esecuzione:
Nome del file: **file1.txt**
Chiave di ricerca: **test**
true
Contenuti di file1.txt:
Questo file è un test per il programma
cerca_parole.go
