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