Esercizio: file di testo - Dipartimento di Informatica e Automazione

Corso di Laurea Ingegneria Informatica
Fondamenti di Informatica 2
Dispensa E08
Esercizi su I/O e classe Object
F. Gasparetti
Marzo 2007
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
1
Contenuti
‰I metodi equals e clone di Object
‰Dato un file di testo su hard drive:
ƒ Leggere il contenuto del file
ƒ Memorizzarne il contenuto del file in una lista di
stringhe
ƒ Visualizzare il contenuto della lista su schermo
ƒ Salvare il contenuto della lista su un secondo file
‰Dati due file di testo su hard drive, confrontarne
il contenuto
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
2
Il metodo equals di Object . . .
‰Il metodo equals è definito nella classe Object
è ritorna true se il parametro è “uguale”
all’oggetto su cui si invoca.
public boolean equals(Object obj)
‰Ma che significa uguale?
‰Object fornisce una implementazione di default
che viene ereditata per ogni classe Java, a
meno che non venga ridefinita dal
programmatore
‰Il metodo di default implementa una
uguaglianza superficiale tra gli argomenti . . .
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
3
Uguaglianza superficiale
‰L’implementazione di default di Object è la
seguente:
ƒ ∀x, y ≠ null, x.equals(y)=true sse x e y
referenziano lo stesso oggetto in memoria, ovvero è
verificata la condizione x == y
‰L’uguaglianza superficiale non è adatta se
quello che vogliamo confrontare è il valore
rappresentato da due oggetti, anche distinti:
Terna x = new Terna(5, 3, 1);
Terna y = new Terna(5, 3, 1);
Terna z = x;
x.equals(z) ⇒ true
x.equals(y) ⇒ false
// ATTENZIONE
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
4
Uguaglianza superficiale
‰Immaginiamo una classe Insieme che mantiene
una collezione di oggetti “distinti”
‰Possiamo pensare di mantenere
l’implementazione di default di equals e
memorizzare una serie di Terne, ma in questo
caso le due terne x e y vengono memorizzate
come due oggetti distinti:
Terna x = new Terna(5, 3, 1);
Terna y = new Terna(5, 3, 1);
‰Nel nostro insieme vogliamo istanze che
rappresentano valori distinti le une dalle altre
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
5
Uguaglianza profonda
‰Se vogliamo confrontare i valori
rappresentati dagli oggetti (uguaglianza
profonda), dobbiamo fornire una
implementazione ad hoc per ogni classe che
andiamo a definire
‰Occorre individuare quali sono le variabili
all’interno della classe che rappresentano
l’oggetto e farne il confronto
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
6
Esempio: equals nella classe Terna
public class Terna {
. . .
public boolean equals(Object o) {
boolean ret = false;
// se l’oggetto o appartiene a una classe diversa
// rispetto a this, i due oggetti non possono
// essere uguali
if (o == null || !getClass().equals(o.getClass())){
ret = false;
} else {
Terna t = (Terna)o;
// nuova condizione di uguaglianza
if (t.riga == riga && t.colonna == colonna)
ret = true;
}
return ret;
} }
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
7
Il metodo equals di Object . . .
‰Alcune classi Java ridefiniscono il metodo
equals in modo opportuno:
ƒ String.equals() = true se le due stringhe
rappresentano la stessa sequenza di caratteri
ƒ Integer.equals() = true se i due oggetti Integer
rappresentano lo stesso valore
ƒ ...
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
8
. . .Il metodo equals di Object
‰Una implementazione di equals deve essere
conforme ad una relazione di equivalenza:
ƒ ∀x ≠ null, x.equals(x) = true (riflessiva)
ƒ ∀x, y ≠ null, x.equals(y) = true sse y.equals(x) = true
(simmetrica)
ƒ ∀x, y, z ≠ null, x.equals(y) = true e y.equals(z) = true
allora x.equals(z) = true (transitiva)
ƒ ∀x, y ≠ null, due o più invocazioni di x.equals(y)
devono ritornare lo stesso valore nel caso in cui
nessuna variabile di x e y venga alterata tra le
invocazioni
ƒ ∀x ≠ null, x.equals(null) = false
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
9
Problemi di memoria condivisa . . .
‰Lo schema realizzativo con condivisione di
memoria può risultare fonte di errori nel caso in
cui si utilizzino strutture dinamiche (ad esempio
Liste) che collegano oggetti che vengono
modificati durante l’esecuzione.
‰Se un oggetto è condiviso da due strutture,
aggiornamenti su una struttura possono
influenzare anche l’altra
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
10
. . .Problemi di memoria condivisa . . .
public class MemoriaCondivisa {
. . .
public static void main(String[] args) {
Lista l1, l2;
l1 = new Lista();
l2 = new Lista();
Terna t1 = new Terna(1,2,3);
Terna t12 = new Terna(2,3,4);
Terna t13 = new Terna(3,4,5);
Terna t22 = new Terna(4,5,6);
Terna t23 = new Terna(5,6,7);
. . .
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
11
. . .Problemi di memoria condivisa . . .
l1 = l1.cons(t13);
l1 = l1.cons(t12);
l1 = l1.cons(t1);
l2 = l2.cons(t23);
l2 = l2.cons(t22);
l2 = l2.cons(t1);
System.out.println("l1:\n"+l1.toString());
System.out.println("l2:\n"+l2.toString()+"\n");
Terna t = (Terna)l1.car();
t.riga++;
t12.riga++;
System.out.println("l1:\n"+l1.toString());
System.out.println("l2:\n"+l2.toString());
}
}
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
12
. . .Problemi di memoria condivisa . . .
‰La terna t1 viene condivisa tra l1 e l2
l1
NodoLista
NodoLista
info
info
t1
t12
NodoLista
info
t13
next
next
NodoLista
NodoLista
NodoLista
info
info
next
Terna t1
riga
colonna
valore
l2
t1
next
http://www.dia.uniroma3.it/~java/fondinf2/
t22
next
Esercizi su I/O e Object
info
t23
next
13
. . .Problemi di memoria condivisa . . .
‰Output del programma:
elementi l1:
123 234 345
elementi l2:
123 456 567
elementi l1:
223 334 345
elementi l2:
223 456 567
La modifica del primo
elemento di l1 ha
influenzato anche l2;
comportamento
generalmente scorretto
La modifica di t12 ha
influenzato correttamente
solo l1
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
14
. . .Problemi di memoria condivisa . . .
‰ Per risolvere il problema ci sono due soluzioni:
1. Creare istanze diverse degli oggetti (anche se
rappresentano gli stessi dati) prima di inserirli nelle
strutture dinamiche:
// Terna t1 = new Terna(1,2,3)
Terna t11 = new Terna(1,2,3);
Terna t12 = new Terna(1,2,3);
. . .
l1 = l1.cons(t11);
l2 = l2.cons(t12);
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
NO!!
15
. . .Problemi di memoria condivisa . . .
2. Richiamare il metodo clone per creare una copia
degli oggetti prima dell’inserimento:
Terna t1 = new Terna(1,2,3);
Terna t12 = (Terna)t1.clone();
. . .
l1 = l1.cons(t1);
l2 = l2.cons(t12);
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
16
. . .Problemi di memoria condivisa . . .
‰ Il metodo clone deve essere definito all’interno
della classe le cui istanze non possono essere
condivise tra due o più oggetti
‰ Il metodo deve creare un oggetto dello stesso
tipo dell’oggetto originale ma indipendente, e
copiare le variabili dall’oggetto originale nel
nuovo oggetto
‰ Le variabili che non possono essere condivise
(come strutture dinamiche annidate) devono
essere a loro volta soggetto di clonazione
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
17
. . .Problemi di memoria condivisa. . .
‰ Se una classe contiene solo tipi primitivi (int,
boolean, etc) o riferimenti a oggetti che non
vengono mai modificati, si può sfruttare
l’implementazione di default di clone, che alloca
spazio per il nuovo oggetto e si occupa di
copiare tutte le variabili primitive
‰ La signatura di clone in Object è:
protected Object clone()
throws CloneNotSupportedException
ma può essere ridefinito public se occorre
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
18
Esempio: clone nella classe Terna
public class Terna implements Cloneable {
. . .
public Object clone()
throws CloneNotSupportedException {
// richiamo l’implementazione di default che crea
// un nuovo oggetto Terna e copia i dati primitivi;
// Object.clone è protetto, ma Terna estende implicitamente
// Object perciò posso richiamare clone di Object.
Terna t = (Terna)super.clone();
// qui copio i dati non primitivi se esistono.
...
// le istruzioni che seguono sono inutili perché se ne
// occupa super.clone();
// t.riga = this.riga;
// t.colonna = this.colonna;
// t.valore = this.valore;
return t;
}
}
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
19
. . .Problemi di memoria condivisa
‰ Ora clone è stato ridefinito con visibilità public,
perciò possiamo richiamarlo ovunque
all’interno del nostro codice:
Terna t1 = new Terna(1,2,3);
// ora la chiamata è corretta
Terna t12 = (Terna)t1.clone();
‰ Quando si definisce clone all’interno di una
classe C, occorre aggiungere l’interfaccia
Cloneable nella definizione di C:
public class Terna implements Cloneable
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
20
Esercizio
‰ Implementare il metodo clone per la classe
Lista, sia nel caso in cui NodoLista contenga
il campo info di tipo String, sia nel caso info
sia di tipo Object.
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
21
Esercizio
‰
Che cosa stampa il seguente frammento di codice?
abstract class PersonaAbstract implements Cloneable {
protected String nome = new String("PersonaAbstract");
public abstract void setXY();
public String getNome() { return nome; }
public Object clone() throws CloneNotSupportedException {
PersonaAbstract p = (PersonaAbstract)super.clone();
p.nome = p.nome + "; PersonaAbstract dopo clone";
return p;
}
} . . .
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
22
Esercizio
class Studente extends PersonaAbstract {
public void setXY() { return; }
public Object clone() throws CloneNotSupportedException{
Studente s = (Studente)super.clone();
s.nome = s.nome + "; Studente dopo clone";
return s;
}
}
public class CloneExample {
public static void provaClonePA(PersonaAbstract p) {
System.out.println("provaClonePA: "+p.getNome());
} . . .
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
23
Esercizio
public static void main(String[] args)
throws Exception {
Studente s = new Studente();
Studente sclone = (Studente)s.clone();
provaClonePA(s);
provaClonePA(sclone);
}
}
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
24
Gestioni di file in Java
‰I/O Java: Un gruppo di classi organizzate
mediante ereditarietà e basate su streams che
rendono meno complicata la lettura e scrittura
di vari tipi di dati su file:
ƒ file di testo: sono documenti, cioè sequenze di
caratteri tipicamente stampabili e interpretabili
dall’utente che possono essere generati da un editor
di testi
ƒ file binario: contengono informazioni interpretabili
solo da un programma specifico, ad esempio il file
Excel “tesina.xls”
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
25
Gli Stream
‰Uno stream è una struttura logica che permette
di leggere o scrivere sequenze di dati
serialmente, uno dopo l’altro, su varie sorgenti
di dati (file, stringhe, buffer, etc).
‰Se trattiamo caratteri e stringhe usiamo la
famiglia di classi Reader/Writer (characterbased I/O) per gli altri tipi di oggetti usiamo la
famiglia di classi InputStream/OutputStream
(byte-oriented I/O)
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
26
Classi derivate da Reader/Writer
‰Alcuni tipi di Reader:
ƒ FileReader: stream che legge caratteri da file
ƒ CharArrayReader: uno stream in lettura da un array di
char
ƒ StringReader: uno stream in lettura da una stringa
‰Alcuni tipi di Writer:
ƒ FileWriter: uno stream che scrive caratteri su file
ƒ CharArrayWriter: StringWriter: uno stream che
colleziona l’output verso un oggetto String
ƒ PrintWriter: stampa in modo formattato caratteri,
stringhe ed altri oggetti su uno stream di output
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
27
Le Classi I/O e l’ereditarietà
‰Le classi Reader hanno il metodo read() per
leggere rispettivamente singoli byte e caratteri
da un File. Ogni classe che deriva da queste
due classi eredita il metodo read ed
eventualmente implementa ulteriori metodi
Reader
→ read()
FileReader
→ read()
. . .
CharArrayReader
→ read()
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
BufferedReader
→ read()
→ readLine()
28
Gli streams di input e output standard
‰In Java la console e la tastiera sono trattati
come particolari stream rispettivamente di
output e input:
Class System {
public static final PrintStream out;
public static final InputStream in;
. . .
}
System.out.println(“scrivo su stream”);
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
29
Composizione di Streams
‰ Molte volte per leggere o scrivere dati componiamo più
streams insieme, dove l’output di uno e preso come
input dal successivo:
myFile.txt
// apertura del file in lettura
FileReader fr = new FileReader(“myFile.txt”);
// lettura bufferizzata dallo stream fr
BufferedReader br = BufferedReader(fr);
String s = br.readLine();
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
30
Esercizio: file di testo . . .
‰ Dato un file di testo su hard drive:
1. Leggere il contenuto del file
2. Memorizzarne il contenuto del file in una lista di
stringhe
3. Visualizzare il contenuto della lista su schermo
4. Salvare il contenuto della lista su un secondo file
‰ Sfruttiamo le seguenti librerie e classi:
1.
2.
3.
4.
Java I/O: streams di input (classi Reader)
Classe Lista (vedi dispense strutture collegate)
Java I/O: stream di output (classe PrintStream)
Java I/O: streams di output (classi Writer)
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
31
. . . Esercizio: file di testo . . .
‰ Realizziamo una classe StringIO dove esistono
tre metodi:
ƒ
ƒ
ƒ
leggiFile: dato un nome (e percorso) di un file,
carica il contenuto all’interno di una struttura
collegata
scriviFile: dato un nome (e percorso) di un file,
scrive il contenuto della struttura collegata sul file
stampa: visualizza su schermo il contenuto della
struttura collegata
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
32
Riprendiamo il NodoLista. . .
‰La classe NodoLista per le liste di stringhe:
class NodoLista {
public String info;
public NodoLista next;
. . .
}
‰Supponiamo di avere disponibili le classi
NodoLista e ListaUso che avevamo definito
precedentemente.
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
33
. . . Esercizio: file di testo . . .
import java.io.*;
public class StringIO {
public static Lista leggiFile(String filename)
throws IOException {
Lista contenutoFile = new Lista();
// apro il file in lettura
FileReader reader = new FileReader(filename);
// BufferedReader per leggere una riga alla volta
BufferedReader br = new BufferedReader(reader);
String linea = null;
. . .
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
34
. . . Esercizio: file di testo . . .
// lettura da file una linea alla volta
while ((linea = br.readLine()) != null) {
// ListaUso per inserire in coda
contenutoFile = ListaUso.aggiungiUltimo
(linea, contenutoFile);
}
// chiudo tutti gli stream
br.close();
reader.close();
return contenutoFile;
}
public void stampa(Lista l) throws IOException {
. . .
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
35
. . . Esercizio: file di testo . . .
while (!l.estVuota()) {
String linea = (String)l.car();
// elimino la testa della lista
l = l.cdr();
System.out.println(linea);
}
}
public static void scriviFile(Lista l, String filename)
throws IOException {
// apro il file in scritto (se esiste lo sovrascrivo)
FileWriter writer = new FileWriter(filename);
// BufferWriter per scrivere una stringa su file
BufferedWriter bw = new BufferedWriter(writer);
. . .
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
36
. . . Esercizio: file di testo . . .
. . .
while (!l.estVuota()) {
String linea = (String)l.car();
l = l.cdr();
bw.write(linea+”\n”);
}
// chiudo gli streams
bw.close();
writer.close();
}
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
37
. . . Esercizio: file di testo . . .
public static void main(String[] args)
throws IOException {
try {
Lista l = StringIO.leggiFile("email.txt");
System.out.println
("--> stampo il contenuto del file <--");
StringIO.stampa(l);
StringIO.scriviFile(l, "email1.txt");
} catch(Exception ex) {
System.out.println(ex.toString());
ex.printStackTrace();
System.exit(1);
}
System.out.println("--> fine senza errori <--");
}
}
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
38
Esercizio: file di testo – eccezioni . . .
‰Le eccezioni vengono catturate nel main, dove
oltre a stampare l’eccezione, visualizziamo
anche lo stack delle chiamate al momento della
eccezione, con il metodo predefinito
printStackTrace della classe Exception
. . .
catch(Exception ex) {
System.out.println(ex.toString());
ex.printStackTrace();
System.exit(1);
}
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
39
. . .Esercizio: file di testo - eccezioni . . .
‰ Lanciamo il programma senza aver creato il file email.txt
Questo è ex.toString()
java.io.FileNotFoundException: email.txt (No such file
or directory)
Questo è l’output di printStackTrace()
java.io.FileNotFoundException: email.txt (No such file
or directory)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>
(FileInputStream.java:106)
at java.io.FileInputStream.<init>
(FileInputStream.java:66)
at java.io.FileReader.<init>(FileReader.java:41)
at StringIO.leggiFile(StringIO.java:8)
at StringIO.main(StringIO.java:46)
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
40
Esercizio: file di testo – posizione dei file
‰Si ottiene lo stesso tipo di eccezione anche se si
sposta il file in una directory diversa da quella
dove si lancia il comando java, cioè dove il
programma si aspetta di trovare il file
‰E’ possibile specificare il percorso completo
insieme al nome del file:
Lista l = StringIO.leggiFile("/tmp/email.txt");
‰Attenzione: in ambiente Windows è diverso:
Lista l = StringIO.leggiFile(“C:\\tmp\\email.txt");
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
41
. . .Esercizio: file di testo ed eccezioni. . .
‰ Dopo aver creato un file email.txt
-=> stampo il contenuto del file <-From:
[email protected]
Subject:
Re: [Nutch-dev] Image Search
Engine Input (General storage of extra data
for use by Nutch)
xyz
-=> fine senza errori <--
‰ E ci aspettiamo di trovare un file email1.txt con lo stesso
contenuto di email.txt
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
42
Esercizio: file di testo (2). . .
‰ Dati due file di testo su hard drive, vogliamo
confrontarne il contenuto per determinare se
sono uguali oppure no
‰ Sfruttiamo la classe precedente, in particolare
il metodo leggiFile per costruire due liste,
una per ogni file di input
‰ Implementiamo il metodo confrontaFile per
il confronto delle due liste che ritorna un
booleano:
ƒ
ƒ
true se i due file contengono lo stesso testo,
false altrimenti
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
43
. . .Esercizio: file di testo (2). . .
public static boolean confrontaFile
(String fn1, String fn2) throws IOException{
// creo le due liste a partire dai nome dei
file
Lista l1 = StringIO.leggiFile(fn1);
Lista l2 = StringIO.leggiFile(fn2);
boolean stop = false;
// continuo fino alla fine di uno dei file
// oppure quando ho trovato due linee che
// non corrispondono
while (!l1.estVuota() && !l2.estVuota() && !stop){
String linea1 = (String)l1.car();
String linea2 = (String)l2.car();
. . .
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
44
. . .Esercizio: file di testo (2). . .
// confronto le due stringhe
if (linea1.equals(linea2)) {
// proseguo con la linea successiva
l1 = l1.cdr();
l2 = l2.cdr();
} else {
stop = true;
}
}
// se sono uscito mentre almeno una delle
// due liste non è vuota, allora i due
// file non sono uguali
return l1.estVuota() && l2.estVuota();
} http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
45
. . .Esercizio: file di testo (2). . .
public static void main(String[] args)
throws IOException {
try {
Lista l = StringIO.leggiFile("email.txt");
System.out.println
("--> stampo il contenuto del file <--");
StringIO.stampa(l);
StringIO.scriviFile(l, "email1.txt");
boolean b;
b = StringIO.confrontaFile
("email.txt", "email1.txt");
System.out.println("uguali? :"+b);
} . . .
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
46
. . .Esercizio: file di testo (2). . .
catch(Exception ex) {
System.out.println(ex.toString());
ex.printStackTrace();
System.exit(1);
}
System.out.println("--> fine senza errori <--");
}
}
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
47
. . .Esercizio: file di testo (2)
‰Output del programma:
-=> stampo il contenuto del file <-From:
[email protected]
Subject:
Re: [Nutch-dev] Image Search
Engine Input (General storage of extra data
for use by Nutch)
xyz
uguali? :true
-=> fine senza errori <--
http://www.dia.uniroma3.it/~java/fondinf2/
Esercizi su I/O e Object
48