File e Flussi File e Flussi
C. Horstmann
C. Horstmann
Fondamenti di programmazione e Java 2
Fondamenti di programmazione e Java 2
3^ edizione Apogeo
3^ edizione Apogeo
trad. Nicola Fanizzi
trad. Nicola Fanizzi
corso di Programmazione, CdS: Informatica TPS
corso di Programmazione, CdS: Informatica TPS
Dip. di Informatica, Università degli studi di Bari
Dip. di Informatica, Università degli studi di Bari
2 2
Obiettivi Obiettivi
Saper leggere e scrivere file di testo Saper leggere e scrivere file di testo
Acquisire familiarità con i concetti di formato binario Acquisire familiarità con i concetti di formato binario e di testo
e di testo
Capire la codifica cifrata delle informazioni Capire la codifica cifrata delle informazioni
Capire quando va usato l’accesso casuale o Capire quando va usato l’accesso casuale o sequenziale ai file
sequenziale ai file
Saper leggere e scrivere oggetti usando la Saper leggere e scrivere oggetti usando la serializzazione
serializzazione
3 3
Leggere e Scrivere File di Testo Leggere e Scrivere File di Testo
Il modo più semplice per leggere file di testo prevede Il modo più semplice per leggere file di testo prevede l’utilizzo della classe
l’utilizzo della classe Scanner Scanner
Per leggere dati da un file presente sul disco, Per leggere dati da un file presente sul disco, occorre dapprima costruire un oggetto di tipo occorre dapprima costruire un oggetto di tipo FileReader
FileReader
Si utilizza tale oggetto come parametro per costruire Si utilizza tale oggetto come parametro per costruire un oggetto di tipo
un oggetto di tipo Scanner Scanner
Per leggere i dati, si possono usare i metodi della classe: Per leggere i dati, si possono usare i metodi della classe:
FileReader reader = new FileReader("input.txt");
FileReader reader = new FileReader("input.txt");
Scanner in = new Scanner(reader);
Scanner in = new Scanner(reader);
4 4
Leggere e Scrivere File di Testo Leggere e Scrivere File di Testo
Per scrivere file di testo usate la classe Per scrivere file di testo usate la classe PrintWriter
PrintWriter e i suoi metodi e i suoi metodi print print e e println
println
Se il file in cui scrivere esiste già, Se il file in cui scrivere esiste già,
viene svuotato prima di scrivervi nuovi dati viene svuotato prima di scrivervi nuovi dati
Se il file non esiste, Se il file non esiste,
viene creato un file vuoto viene creato un file vuoto
PrintWriter out = new PrintWriter("output.txt");
PrintWriter out = new PrintWriter("output.txt");
5 5
Leggere e Scrivere File di Testo Leggere e Scrivere File di Testo
Usate, poi, i consueti metodi Usate, poi, i consueti metodi print print e e println println per inviare numeri, oggetti e stringhe all'istanza di per inviare numeri, oggetti e stringhe all'istanza di PrintWriter
PrintWriter
Quando avete terminato di scrivere in un oggetto di Quando avete terminato di scrivere in un oggetto di tipo
tipo PrintWriter PrintWriter , accertatevi di chiuderlo , accertatevi di chiuderlo
Se il programma termina l’esecuzione senza aver chiuso Se il programma termina l’esecuzione senza aver chiuso
out.println(29.95);
out.println(29.95);
out.println(new Rectangle(5, 10, 15, 25));
out.println(new Rectangle(5, 10, 15, 25));
out.println("Hello, World!");
out.println("Hello, World!");
out.close();
out.close();
6 6
Esempio di Programma Esempio di Programma
Legge tutte le righe presenti in un file di dati in Legge tutte le righe presenti in un file di dati in ingresso e le invia ad un file di uscita,
ingresso e le invia ad un file di uscita,
facendo precedere a ciascuna riga di testo il facendo precedere a ciascuna riga di testo il
corrispondente numero di riga corrispondente numero di riga
Se il file d’ingresso è: Se il file d’ingresso è:
Mary had a little lamb Mary had a little lamb
Whose fleece was white as snow.
Whose fleece was white as snow.
And everywhere that Mary went, And everywhere that Mary went, The lamb was sure to go!
The lamb was sure to go!
7 7
Esempio di programma Esempio di programma
Allora il programma produce il seguente file: Allora il programma produce il seguente file:
I numeri di riga sono racchiusi tra delimitatori I numeri di riga sono racchiusi tra delimitatori /* /*
*/ */ in modo che il programma possa essere in modo che il programma possa essere
utilizzato per numerare file di codice sorgente Java utilizzato per numerare file di codice sorgente Java
/* 1 */ Mary had a little lamb /* 1 */ Mary had a little lamb
/* 2 */ Whose fleece was white as snow.
/* 2 */ Whose fleece was white as snow.
/* 3 */ And everywhere that Mary went, /* 3 */ And everywhere that Mary went, /* 4 */ The lamb was sure to go!
/* 4 */ The lamb was sure to go!
8 8
LineNumberer.java LineNumberer.java
01: import java.io.FileReader;
01: import java.io.FileReader;
02: import java.io.IOException;
02: import java.io.IOException;
03: import java.io.PrintWriter;
03: import java.io.PrintWriter;
04: import java.util.Scanner;
04: import java.util.Scanner;
05: 05:
06: public class LineNumberer 06: public class LineNumberer 07: {
07: {
08: public static void main(String[] args) 08: public static void main(String[] args) 09: {
09: {
10: Scanner console = new Scanner(System.in);
10: Scanner console = new Scanner(System.in);
11: System.out.print("Input file: ");
11: System.out.print("Input file: ");
12: String inputFileName = console.next();
12: String inputFileName = console.next();
13: System.out.print("Output file: ");
13: System.out.print("Output file: ");
14: String outputFileName = console.next();
14: String outputFileName = console.next();
15: 15:
16: try 16: try 17: { 17: {
18: FileReader reader = new FileReader(inputFileName);
18: FileReader reader = new FileReader(inputFileName);
19: Scanner in = new Scanner(reader);
19: Scanner in = new Scanner(reader);
9 9
LineNumberer.java LineNumberer.java
22:
22:
23: while (in.hasNextLine()) 23: while (in.hasNextLine()) 24: {
24: {
25: String line = in.nextLine();
25: String line = in.nextLine();
26: out.println("/* " + lineNumber + " */ " + line);
26: out.println("/* " + lineNumber + " */ " + line);
27: lineNumber++;
27: lineNumber++;
28: } 28: } 29: 29:
30: out.close();
30: out.close();
31: } 31: }
32: catch (IOException exception) 32: catch (IOException exception) 33: {
33: {
34: System.out.println("Error processing file:"
34: System.out.println("Error processing file:"
+ exception);
+ exception);
35: }
35: }
36: }
36: }
10 10
Una Finestra di Dialogo
Una Finestra di Dialogo
11 11
Una Finestra di Dialogo Una Finestra di Dialogo
JFileChooser chooser = new JFileChooser();
JFileChooser chooser = new JFileChooser();
FileReader in = null;
FileReader in = null;
if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) { File selectedFile = chooser.getSelectedFile(); { File selectedFile = chooser.getSelectedFile();
reader = new FileReader(selectedFile); reader = new FileReader(selectedFile);
. . . . . .
} }
12 12
Formato di Testo Formato di Testo
Esistono due modi fondamentalmente diversi di Esistono due modi fondamentalmente diversi di memorizzare i dati:
memorizzare i dati:
In formato testo In formato testo
In formato binario In formato binario
13 13
Formato di Testo Formato di Testo
Nel formato testo i dati sono rappresentati in una Nel formato testo i dati sono rappresentati in una forma leggibile dagli esseri umani come una
forma leggibile dagli esseri umani come una sequenza di caratteri
sequenza di caratteri
Per esempio, il numero intero 12345 viene memorizzato Per esempio, il numero intero 12345 viene memorizzato come una sequenza di cinque caratteri:
come una sequenza di cinque caratteri:
'1' '2' '3' '4' '5' '1' '2' '3' '4' '5'
Per elaborare dati in ingresso e in uscita dovete Per elaborare dati in ingresso e in uscita dovete usare le classi
usare le classi Reader Reader e e Writer Writer e le loro e le loro sottoclassi
sottoclassi
Per leggere: Per leggere:
FileReader reader = new FileReader("input.txt");
FileReader reader = new FileReader("input.txt");
14 14
Formato Binario Formato Binario
Nel formato binario i dati sono rappresentati da byte Nel formato binario i dati sono rappresentati da byte
In formato binario il numero intero 12345 viene registrato In formato binario il numero intero 12345 viene registrato come una sequenza di quattro byte
come una sequenza di quattro byte 0 0 48 57 0 0 48 57
Se memorizzate le informazioni in forma binaria, Se memorizzate le informazioni in forma binaria, come sequenza di byte, dovete usare le classi come sequenza di byte, dovete usare le classi InputStream
InputStream e e OutputStream OutputStream e le loro e le loro sottoclassi
sottoclassi
La memorizzazione binaria è più compatta e più La memorizzazione binaria è più compatta e più efficiente
efficiente
15 15
Formato Binario Formato Binario
Per leggere dati binari da un file su disco si crei un Per leggere dati binari da un file su disco si crei un oggetto di tipo
oggetto di tipo FileInputStream FileInputStream
Si usi oggetti di tipo Si usi oggetti di tipo FileWriter FileWriter e e FileOutputStream
FileOutputStream per scrivere dati in un file per scrivere dati in un file su disco in forma di testo o, rispettivamente, binaria su disco in forma di testo o, rispettivamente, binaria
FileInputStream inputStream FileInputStream inputStream
= new FileInputStream("input.bin");
= new FileInputStream("input.bin");
FileOutputStream outputStream FileOutputStream outputStream
= new FileOutputStream("output.bin");
= new FileOutputStream("output.bin");
16 16
Leggere un Singolo Carattere da Leggere un Singolo Carattere da
un File in Formato Testo un File in Formato Testo
La classe La classe Reader Reader ha un metodo, ha un metodo, read read , che , che legge un carattere alla volta
legge un carattere alla volta
Il metodo Il metodo read read di fatto restituisce un dato di tipo di fatto restituisce un dato di tipo int int
Alla fine dei dati, Alla fine dei dati, read read restituisce restituisce –1 –1
Reader reader = . . .;
Reader reader = . . .;
int next = reader.read();
int next = reader.read();
char c;
char c;
if (next != -1) if (next != -1) c = (char) next;
c = (char) next;
17 17
Leggere un Singolo Carattere da Leggere un Singolo Carattere da
un File in Formato Testo un File in Formato Testo
La classe La classe InputStream InputStream ha un metodo ha un metodo read read per leggere un byte alla volta
per leggere un byte alla volta
Restituisce un dato di tipo Restituisce un dato di tipo int int , che può essere il byte , che può essere il byte che è stato inserito
che è stato inserito
Restituisce il numero intero Restituisce il numero intero –1 –1 , se è stata raggiunta la , se è stata raggiunta la fine del flusso
fine del flusso
InputStream in = . . .;
InputStream in = . . .;
int next = in.read();
int next = in.read();
byte b; if byte b; if (next != -1) (next != -1)
b = (byte) next;
b = (byte) next;
18 18
Formato Testo e Binario Formato Testo e Binario
Le classi Le classi Writer Writer e e FileOutputStream FileOutputStream
hanno un metodo write per scrivere, rispettivamente, hanno un metodo write per scrivere, rispettivamente,
un singolo carattere o byte un singolo carattere o byte
Questi metodi basilari sono gli unici metodi di lettura Questi metodi basilari sono gli unici metodi di lettura e scrittura forniti dalle classi che leggono e scrivono e scrittura forniti dalle classi che leggono e scrivono
un file un file
Il pacchetto dei flussi di Java si basa sul principio Il pacchetto dei flussi di Java si basa sul principio che ciascuna classe deve avere una
che ciascuna classe deve avere una responsabilità responsabilità ben precisa
ben precisa
19 19
Formato Testo e Binario Formato Testo e Binario
Il compito di un oggetto di tipo Il compito di un oggetto di tipo FileInputStream
FileInputStream è quello di interagire con i è quello di interagire con i file, cioè di acquisire dati sotto forma di byte, non di file, cioè di acquisire dati sotto forma di byte, non di
analizzarli analizzarli
Se volete leggere numeri, stringhe o altri oggetti, Se volete leggere numeri, stringhe o altri oggetti, dovete combinare la classe con altre classi
dovete combinare la classe con altre classi
20 20
Un Programma di Crittografia Un Programma di Crittografia
Il programma cifra un file Il programma cifra un file
Mescola i dati in modo che siano illeggibili tranne per chi Mescola i dati in modo che siano illeggibili tranne per chi conosca il metodo di decifrazione e la corrispondente conosca il metodo di decifrazione e la corrispondente
parola segreta parola segreta
Useremo un metodo che era conosciuto ai tempi di Useremo un metodo che era conosciuto ai tempi di Giulio Cesare
Giulio Cesare
Si sceglie una chiave di cifratura, che in questo caso è un Si sceglie una chiave di cifratura, che in questo caso è un numero compreso tra 1 e 25
numero compreso tra 1 e 25
Esempio Esempio
se la chiave è 3, si sostituisce A con D, B con E, e così via
se la chiave è 3, si sostituisce A con D, B con E, e così via
21 21
Un programma di crittografia Un programma di crittografia
Figura 2:
Il codice di Cesare
Testo normale
Testo cifrato
Per la decifrazione, si usa semplicemente il valore Per la decifrazione, si usa semplicemente il valore opposto della chiave (negativo)
opposto della chiave (negativo)
22 22
Elaborazione di Dati Binari Elaborazione di Dati Binari
int next = in.read();
int next = in.read();
if (next == -1) done = true;
if (next == -1) done = true;
else else { {
byte b = (byte) next;
byte b = (byte) next; //call the method to encrypt the byte //call the method to encrypt the byte byte c = encrypt(b);
byte c = encrypt(b);
out.write(c); out.write(c);
} }
23 23
Encryptor.java Encryptor.java
01: import java.io.File;
01: import java.io.File;
02: import java.io.FileInputStream;
02: import java.io.FileInputStream;
03: import java.io.FileOutputStream;
03: import java.io.FileOutputStream;
04: import java.io.InputStream;
04: import java.io.InputStream;
05: import java.io.OutputStream;
05: import java.io.OutputStream;
06: import java.io.IOException;
06: import java.io.IOException;
07: 07:
08: /**
08: /**
09: un cifratore cifra file usando la crittyografia di Cesare.
09: un cifratore cifra file usando la crittyografia di Cesare.
10: Per la decifrazione, usate un cifratore con la chiave 10: Per la decifrazione, usate un cifratore con la chiave 11: opposta a quella di cifratura.
11: opposta a quella di cifratura.
12: */
12: */
13: public class Encryptor 13: public class Encryptor 14: {
14: {
15: /**
15: /**
16: Costruisce un cifratore.
16: Costruisce un cifratore.
24 24
Encryptor.java Encryptor.java
19: public Encryptor(int aKey) 19: public Encryptor(int aKey) 20: {
20: {
21: key = aKey;
21: key = aKey;
22: } 22: } 23: 23:
24: /**
24: /**
25: cifra il contenuto di un file.
25: cifra il contenuto di un file.
26: @param inFile il nome del file in ingresso 26: @param inFile il nome del file in ingresso 27: @param outFile il nome del file in uscita 27: @param outFile il nome del file in uscita 28: */
28: */
29: public void encryptFile(String inFile, String outFile) 29: public void encryptFile(String inFile, String outFile) 30: throws IOException
30: throws IOException 31: {
31: {
32: InputStream in = null;
32: InputStream in = null;
33: OutputStream out = null;
33: OutputStream out = null;
34: 34:
35: try
35: try
25 25
Encryptor.java Encryptor.java
37: in = new FileInputStream(inFile);
37: in = new FileInputStream(inFile);
38: out = new FileOutputStream(outFile);
38: out = new FileOutputStream(outFile);
39: encryptStream(in, out);
39: encryptStream(in, out);
40: } 40: }
41: finally 41: finally 42: {
42: {
43: if (in != null) in.close();
43: if (in != null) in.close();
44: if (out != null) out.close();
44: if (out != null) out.close();
45: } 45: } 46: }
46: } 47: 47:
48: /**
48: /**
49: Cifra il contenuto di un flusso.
49: Cifra il contenuto di un flusso.
50: @param in il flusso di ingresso 50: @param in il flusso di ingresso 51: @param out il flusso di uscuta 51: @param out il flusso di uscuta 52: */
52: */
26 26
Encryptor.java Encryptor.java
53: public void encryptStream(InputStream in, OutputStream 53: public void encryptStream(InputStream in, OutputStream out) out)
54: throws IOException 54: throws IOException 55: {
55: {
56: boolean done = false;
56: boolean done = false;
57: while (!done) 57: while (!done) 58: {
58: {
59: int next = in.read();
59: int next = in.read();
60: if (next == -1) done = true;
60: if (next == -1) done = true;
61: else 61: else 62: { 62: {
63: byte b = (byte) next;
63: byte b = (byte) next;
64: byte c = encrypt(b);
64: byte c = encrypt(b);
65: out.write(c);
65: out.write(c);
66: }
66: }
67: }
67: }
68: }
68: }
27 27
Encryptor.java Encryptor.java
70: /**
70: /**
71: Cifra un byte.
71: Cifra un byte.
72: @param b il byte da cifrare 72: @param b il byte da cifrare 73: @return il byte cifrato
73: @return il byte cifrato 74: */
74: */
75: public byte encrypt(byte b) 75: public byte encrypt(byte b) 76: {
76: {
77: return (byte) (b + key);
77: return (byte) (b + key);
78: } 78: } 79: 79:
80: private int key;
80: private int key;
81: }
81: }
28 28
EncryptorTester.java EncryptorTester.java
01: import java.io.IOException;
01: import java.io.IOException;
02: import java.util.Scanner;
02: import java.util.Scanner;
03: 03:
04: /**
04: /**
05: Un programma per collaudare il cifratore con 05: Un programma per collaudare il cifratore con
il codice di Cesare. il codice di Cesare.
06: */
06: */
07: public class EncryptorTester 07: public class EncryptorTester 08: {
08: {
09: public static void main(String[] args) 09: public static void main(String[] args) 10: {
10: {
11: Scanner in = new Scanner(System.in);
11: Scanner in = new Scanner(System.in);
12: try 12: try 13: { 13: {
14: System.out.print("Input file: ");
14: System.out.print("Input file: ");
15: String inFile = in.next();
15: String inFile = in.next();
16: System.out.print("Output file: ");
29 29
EncryptorTester.java EncryptorTester.java
18: System.out.print("Encryption key: ");
18: System.out.print("Encryption key: ");
19: int key = in.nextInt();
19: int key = in.nextInt();
20: Encryptor crypt = new Encryptor(key);
20: Encryptor crypt = new Encryptor(key);
21: crypt.encryptFile(inFile, outFile);
21: crypt.encryptFile(inFile, outFile);
22: } 22: }
23: catch (IOException exception) 23: catch (IOException exception) 24: {
24: {
25: System.out.println("Error processing file: "
25: System.out.println("Error processing file: "
+ exception);
+ exception);
26: } 26: } 27: } 27: } 28: } 28: } 29: 29:
30: 30:
30 30
Crittografia con Chiave Pubblica Crittografia con Chiave Pubblica
Figura 3
Vediamoci Vediamoci
alla festa alla festa in toga in toga
Testo normale
Testo normale testo testo
decifrato decifrato
Testo cifrato Testo cifrato
Chiave pubblica di Bob Chiave pubblica di Bob
chiave privata di chiave privata di
Bob Bob
Vediamoci Vediamoci
alla festa
alla festa
in toga
in toga
31 31
Accesso Casuale e Accesso Casuale e Accesso Sequenziale Accesso Sequenziale
Accesso sequenziale Accesso sequenziale
Un file viene elaborato un byte alla volta Un file viene elaborato un byte alla volta
può essere poco efficiente può essere poco efficiente
Accesso casuale Accesso casuale
consente di accedere a posizioni arbitrarie nel file consente di accedere a posizioni arbitrarie nel file
Solo i file su disco forniscono l’accesso casuale Solo i file su disco forniscono l’accesso casuale