Streams e Input/output. Scansione e Formattazione di un testo Streams Testuali e Binarie Streams di...
-
Upload
franca-sanna -
Category
Documents
-
view
216 -
download
0
Transcript of Streams e Input/output. Scansione e Formattazione di un testo Streams Testuali e Binarie Streams di...
Streamse
Input/output
• Scansione e Formattazione di un testo
• Streams Testuali e Binarie
• Streams di dati primitivi
• Streams di oggetti (serializzazione)
• File ad accesso diretto
Scansione
Scanner
• Da Java 1.5 il modo più semplice di leggere da una stream di tipo testo: Uno scanner suddivide la stream in tokens utilizzando
delimitatori (per default spazi, tabs, newlines …) i tokens possono essere convertiti in valor di tipo
primitivo e stringa utilizzando i metodi della classe
Continua…
Scanner in = new Scanner(File(“input.txt“));
Scansione
Scanner
• Per effettuare la scansione dell’input utilizziamo i metodi forniti dalla classe
• Metodi di scansione generica String next(), bool hasNext()
cercano il prossimo token (ignorando i delimitatori)
• Metodi di scansione specifica per tipo int nextInt(), bool hasNextInt() ...
Continua…
Scansione
Scanner
• non solo per input da file …
Continua…
Scansione
Output Formattato
• Per formattare un file di testo costruiamo un PrintWriter sul file
• Se il file esiste al momento della creazione il contenuto viene cancellato
• Se il file non esiste, la chiamata al costruttore crea un nuovo file, vuoto
PrintWriter out = new PrintWriter("output.txt");
Continua…
Output Formattato
• Utilizziamo print e println per scrivere con PrintWriter:
• File aperti (in scrittura) devono essere sempre chiusi
• Altrimenti non abbiamo garanzie che l’output sia effettuato
out.println(29.95); out.println(new Rectangle(5, 10, 15, 25)); out.println("Hello, World!");
out.close();
Continua…
Output Formattato
PrintWriter
• non solo per output sul file …
Continua…
Output Formattato
PrintWriter out = new PrintWriter("output.txt");
Esempio
• Legge tutte le linee di un file (di tipo testo) e le copia in output precedute dal numero di linea
Continua…
Mary had a little lamb Whose fleece was white as snow. And everywhere that Mary went, The lamb was sure to go!
/* 1 */ Mary had a little lamb /* 2 */ Whose fleece was white as snow. /* 3 */ And everywhere that Mary went, /* 4 */ The lamb was sure to go!
File LineNumberer.java
import java.io.FileReader;import java.io.IOException;import java.io.PrintWriter;import java.util.Scanner;
public class LineNumberer{ public static void main(String[] args) { Scanner console = new Scanner(System.in); System.out.print("Input file: "); String inputFileName = console.next(); System.out.print("Output file: "); String outputFileName = console.next();
try {
Continua…
File LineNumberer.java FileReader reader = new FileReader(inputFileName); Scanner in = new Scanner(reader); PrintWriter out = new PrintWriter(outputFileName); int lineNumber = 1; while (in.hasNextLine()) { String line = in.nextLine(); out.println("/* " + lineNumber + " */ " + line); lineNumber++; } out.close(); } catch (IOException exception) { System.out.println("Error processing file:"+ exception); } }}
Domande
• Che succede se forniamo lo stesso nome per i due file di input e output?
• Che succede se il nome fornito dall’utente non corrisponde ad alcune file?
Risposte
• Creando il PrintWriter si azzera il contenuto del file di output. Anche il file di input è quindi nullo, e dunque il ciclo termina immediatamente.
• Il programma cattura una FileNotFoundException, stampa un messaggio di errore e termina.
Streams
• Due modalità di memorizzazione e codifica dei dati: formato testo formato binario
• Due corrispondenti gerarchie di streams nella libreria java.io
Streams di Testo
• Utilizzate per la lettura scrittura di testo
• Sono sequenze di caratteri l’intero 12.345 è memorizzato come la
seguenza di caratteri '1' '2' '3' '4' '5'
Continua…
Streams di Testo
• Reader, Writer classi astratte che fanno da radici per gerarchia delle stream di testo per le operazioni di input e output
• Molte sottoclassi, alcune già viste FileReader, Scanner, ...
FileWriter, PrintWriter ...
Continua…
Streams di Testo
Continua…
• Le classi Reader, Writer forniscono i metodi base per l’input/output
• Reader.read() restituisce il prossimo carattere, come intero -1 se non esiste un nuovo carattere (nd of file) si blocca in attesa di input da tastiera
Reader reader = new FileReader(“input.txt”);int next = reader.read(); char c; if (next != -1) c = (char) next;
Streams di Testo
• Le classi Reader, Writer forniscono i metodi base per l’input/output
• Write.write(char c) scrive il carattere sulla stream
Streams Binarie
• Utilizzate la manipolazione di dati in formato binario
• Dati rappresentati come sequenze di bytes l’intero 12.345 è memorizzato come la
seguenza di quattro bytes 0 0 48 57
• Rappresentazione più compatta ed efficiente
Continua…
Streams Binarie
• InputStream, OutputStream classi astratte che fanno da radici per gerarchia delle stream binarie per le operazioni di input e output
• Anche qui molte sottoclassi concrete FileInputStream, ObjectInputStream, ... FileOutputStream,ObjectOutputStream, ...
Continua…
Streams Binarie
Continua…
• Le classi InputStream, OutputStream forniscono i metodi base per l’input/output
• InputStream.read() restituisce il prossimo carattere, come intero -1 se non esiste un nuovo carattere (end of file)
• OutputStream.write(byte b) scrive b sullo stream
DataStreams
• Utilizzate per leggere e scrivere in formato binario di tipi primitivi byte, char, short, ..., double, boolean,
• Due classi: DataInputStream, DataOutputStream
• Forniscono metodi per manipolare dati primitivi, readBoolean / writeBoolean readChar / writeChar readInt / writeInt ... / ...
Input/output strutturato
• Per operazioni più complesse utilizziamo le sottoclassi, come classi decorators
Reader reader = new FileReader(“input.txt”));Scanner input = new Scanner(reader);
Writer writer = new FileWriter(“output.txt”));PrintWriter output = new PrintWriter(writer));
InputStream is = new FileInputStream(“in.bin”));DataInputStream dis = new DataInputStream(is);
OutputStream os = new FileOutputStream(“out.bin”));DataOutputStream dos = new DataOutputStream(os);
DataOutputStreams
• Scrive un array di double su un file
void writeData(double[] data, String file) throws IOException {
DataOutputStream out = new DataOutputStream(
new FileOutputStream(file));out.writeInt(data.length());for (int i = 0; i < data.length; i++)
out.writeDouble(data[i]);out.close();
}
DataInputStreams
• Legge un file di double, in cui il primo elemento è un intero che rappresenta il numero di valori contenuti nel file
• restituisce un array con i valori letti
double[] readData(String file) throws IOException {DataInputStream in =
new DataInputStream(new FileInputStream(file));
double[] data = new double[in.readInt()]; for (int i = 0; i < data.length; i++)
data[i] = in.readDouble();in.close(); return data;
}
File Streams
• Permettono di utilizzare files come streams
• Due coppie di classi FileInputStream / FileOutputStream FileReader / FileWriter
• Ognuna di queste classi permette di costruire una stream su un file a partire da: una stringa, il nome del file un oggetto di tipo File un oggetto di tipo FileDescriptor
La classe File
• Rappresentazione astratta del nome e proprietà di files e directories.
• Diversi sistemi operativi utilizzano diverse sintassi per i nomi di files: la classe File fornisce una rappresentazione indipendente dal sistema
• Un nome è rappresentato da una stringa prefissa che rappresenta la radice la radice del file
system : ad esempio “/” in unix e “\\” per una sequenza di zero o più nomi, ciascuno dei quali rappresenta
un passo sul cammino al file. Tutti i nomi sono directories, ad eccezione dell’ultimo che può essere una directory o un file
ObjectStreams
• Estensioni delle DataStreams a valori di tipo riferimento
• Classi: ObjectInputStream e ObjectOutputStream
• serializzazione/deserializzazione conversione di un oggetto in/da una stream di bytes
• Metodi ObjectOutputStream.writeObject() ObjectInputStream.readObject()
ObjectStreams
• writeObject(Object obj): scrive sulla stream una sequenza di bytes
corrispondente al grafo che costituisce obj il grafo include tutti i campi primitivi dell’oggetto e tutti
gli oggetti raggiungibili da riferimenti presenti in obj; esclusi i campi marcati transient
• Object readObject() legge dalla stream una sequenza di bytes che
rappresenta un grafo e restituisce l’oggetto corrispondente
writeObject()
• Scrive un intero oggetto sulla stream
• Anche una lista viene scritta da una sola writeObject
BankAccount b = . . .; ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream("bank.dat")); out.writeObject(b);
ArrayList<BankAccount> a = new ArrayList<BankAccount>(); // ... aggiungi BankAccounts ad a ... out.writeObject(a);
readObject()
• Restituisce un riferimento di tipo Object Necessario ricordare i tipi degli oggetti scritti sulla
stream per leggerli ed utilizzare cast
• può lanciare ClassNotFoundException eccezione controllata necessario catturare o dichiarare
Continued…
BankAccount b = (BankAccount) in.readObject();
Serializable
• Oggetti scritti su una object stream devono appartenere a classi che implementano l’interfaccia Serializable
• Serializable è una interfaccia marker non ha metodi, segnala una proprietà.
class BankAccount implements Serializable { . . . }
Continua…
Serializable
• Ogni oggetto scritto sulla stream viene associato ad un numero seriale
• Se lo stesso oggetto viene scritto due volte, la seconda volta si scrive solo il numero seriale, non l’oggetto
• In fase di lettura, ogni input alloca un nuovo oggetto, a meno che la lettura non incontri un numero seriale duplicato, nel qual caso si restituisce un riferimento allo stesso oggetto
File Serialtester.java
public static void main(String[] args) throws IOException, ClassNotFoundException { Bank bank; File f = new File("bank.dat"); if (f.exists()) { ObjectInputStream in = new ObjectInputStream (new FileInputStream(f)); bank = (Bank) in.readObject(); in.close(); } else { bank = new Bank(); bank.addAccount(new BankAccount(1001, 20000)); bank.addAccount(new BankAccount(1015, 10000)); }
Continua…
File Serialtester.java
// Esegui un deposito BankAccount a = firstBankOfJava.find(1001); a.deposit(100); System.out.println(a.getAccountNumber() + ":" + a.getBalance()); a = firstBankOfJava.find(1015); System.out.println(a.getAccountNumber() + ":" + a.getBalance());
ObjectOutputStream out = new ObjectOutputStream (new FileOutputStream(f)); out.writeObject(firstBankOfJava); out.close(); }}
Serializzazione user-defined
• In alcune situazioni la serializzazione default può risultare scorretta/inefficiente.
• hash è transient, perché si può calcolare dal nome
class Nome implements Serializable { private String nome; private transient int hash; public Nome (String nome) { this.nome = nome; hash = nome.hashCode();} . . . }
Continua…
Serializzazione user-defined
• Il campo hash è transient,
• Ma allora deserializzando un Nome perdiamo il suo codice hash …
class Nome implements Serializable { private String nome; private transient int hash; public Nome (String nome) { this.nome = nome; hash = nome.hashCode();} . . . }
Continua…
Serializzazione user-defined
• Sia C la nostra classe Serializable
• Definiamo in C due metodi: void writeObject(ObjectOutputStream) void readObject(ObjectInputStream)
• Invocati automaticamente da ObjectOutputStream.writeObject(Object o)quando l’argomento ha tipo C
ObjectInputStream.readObject()per leggere argomenti scritti da C.writeObject(ObjectOutputStream)
Nome: serializzazione corretta
class Nome implements Serializable {
private String nome;private transient int hash;
public Nome (String nome) { this.nome = nome; hash = name.hasCode();}
private void writeObject(ObjectOutputStream out)throws IOException
{ out.writeUTF(nome); }
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
{ nome = in.readUTF(); hash = nome.hashCode();}}
Continua…
Nome: serializzazione corretta
• writeObject / readObject dichiarano IOException invocano metodi che potrebbero lanciarle.
• readObject dichiara ClassNotFoundException : deserializzazione richiede la costruzione oggetti di classi che
devono essere caricate (e quindi trovate) per invocarne i costruttori
• sono private: per protezione il processo di serializzazione bypassa questo vincolo, per
invocare comunque i due metodi, utilizzando i meccanismi di riflessione per disattivare i livelli di accesso
File ad Accesso Casuale
• Permette di accedere a punti arbitrari di un file
• Solo per file memorizzati su disco System.in e System.out non supportano queste
operazioni
• Ogni file su disco ha uno stato che determina la posizione corrente di lettura e/o scrittura
Accesso Casuale
RandomAccessFile
• Possiamo aprire un file in diverse modalità Read-only ("r") Read-write ("rw") Write-only ("w")
• Il metodo seek() permette di spostare il file-pointer ad una specifica posizione
RandomAccessFile f = new RandomAcessFile("bank.dat","rw");
f.seek(n);
Continua…
RandomAccessFile
• f.getFilePointer() restituisce la posizione corrente del file pointer
• f.length() restituisce la lunghezza del file
// tipo "long" perchè un file può avere grandi dimensioni
long n = f.getFilePointer();
fileLength =
Continua…
RandomAccessFile
• Memorizza dati in formato binario
• readInt e writeInt leggono e scrivono interi su 4 bytes
• readDouble e writeDouble utilizzano 8 bytes
Esempio
• Utilizziamo un file ad accesso casuale per memorizzare un insieme di conti bancari memorizziamo solo la parte dati di ciascun conto numero di conto e saldo
• Il programma permette di selezionare un conto ed eseguire operazioni di deposito/prelievo …
Esempio
• Calcolo del numero di conti sul file
public int size() throws IOException { return (int) (file.length() / RECORD_SIZE); // RECORD_SIZE = 12 bytes: // 4 bytes per il numero // 8 bytes for il saldo
}
Esempio
• Accesso (in lettura) all’n-esimo conto sul file
public BankAccount read(int n) throws IOException { file.seek(n * RECORD_SIZE); int accountNumber = file.readInt(); double balance = file.readDouble(); return new BankAccount(accountNumber, balance); }
Esempio
• Accesso (in scrittura) all’n-esimo conto
public void write(int n, BankAccount account) throws IOException { file.seek(n * RECORD_SIZE); file.writeInt(account.getAccountNumber()); file.writeDouble(account.getBalance()); }
File BankDatatester.java
import java.io.IOException;import java.io.RandomAccessFile;import java.util.Scanner;
/** Test per file ad accesso diretto. Un loop di interazione con l’utente in cui si agisce su un conto esistente o se ne crea uno nuovo..*/public class BankDataTester{ public static void main(String[] args) throws IOException { Scanner in = new Scanner(System.in); BankData data = new BankData(); try Continua…
File BankDatatester.java
{ data.open("bank.dat"); boolean done = false; while (!done) { System.out.print("Account number: "); int accountNumber = in.nextInt(); System.out.print("Amount to deposit: "); double amount = in.nextDouble(); int position = data.find(accountNumber); BankAccount account; if (position >= 0) { account = data.read(position); account.deposit(amount);
Continued…
File BankDatatester.java
System.out.println("new balance=" + account.getBalance()); } else // Add account { account = new BankAccount(accountNumber, amount); position = data.size(); System.out.println("adding new account"); } data.write(position, account); System.out.print("Done? (Y/N) "); String input = in.next(); if (input.equalsIgnoreCase("Y")) done = true; } } Continua…
File BankDatatester.java
finally { data.close(); } } }
File BankData.java
import java.io.IOException;import java.io.RandomAccessFile;
/** * Una classe associata ad un file contenente i dati . */ public class BankData { /** * Costruisce una BankData senza associarla ad un file */ public BankData() { file = null; } Continua…
File BankData.java
/** * Apre il file di dati. * @param il nome del file con i dati */ public void open(String filename) throws IOException { if (file != null) file.close(); file = new RandomAccessFile(filename, "rw"); }
Continua…
File BankData.java
/** * Restituisce il numero di conti sul file */ public int size() throws IOException { return (int) (file.length() / RECORD_SIZE); } /** * Chiude il file */ public void close() throws IOException { if (file != null) file.close(); file = null; } Continua…
File BankData.java
/** * Legge un record dal file. */ public BankAccount read(int n) throws IOException { file.seek(n * RECORD_SIZE); int accountNumber = file.readInt(); double balance = file.readDouble(); return new BankAccount(accountNumber, balance); }
Continua…
File BankData.java
/** * Trova la posizione del conto con il dato numero * @result = la posizione, -1 se il conto non viene trovato */ public int find(int accountNumber) throws IOException { for (int i = 0; i < size(); i++) { file.seek(i * RECORD_SIZE); int a = file.readInt(); if (a == accountNumber) // trovato return i; } return -1; // nessun match sull’intero file }
Continua…
File BankData.java
/** Salva un record sul tile @param n l’indice del conto sul file @param il conto da salvare */ public void write(int n, BankAccount account) throws IOException { file.seek(n * RECORD_SIZE); file.writeInt(account.getAccountNumber()); file.writeDouble(account.getBalance()); } private RandomAccessFile file;
Continua…
File BankData.java
public static final int INT_SIZE = 4; public static final int DOUBLE_SIZE = 8; public static final int RECORD_SIZE = INT_SIZE + DOUBLE_SIZE;}
Output
Account number: 1001 Amount to deposit: 100 adding new account Done? (Y/N) N Account number: 1018 Amount to deposit: 200 adding new account Done? (Y/N) N Account number: 1001 Amount to deposit: 1000 new balance=1100.0 Done? (Y/N) Y
Esempio: Text Editor Grafico
MenuItem
Menu
Menu
MenuBar
MenuItem
Menu Items
• Aggiungiamo i menu items e i menu in cascata con il metodo add add():
• Un menu item genera eventi eventi, più precisamente ActionEvents
JMenuItem fileExitItem = new JMenuItem("Exit"); fileMenu.add(fileExitItem);
Continua…
Menu Items
• Aggiungiamo quindi un listener a ciascun item:
• Il listener viene associato agli items del menu, non al menu o alla barra dei menu
fileExitItem.addActionListener(listener);
Struttura dei Menu Items
:
EditorMenuItem<abstract>
PasteMenuItemClearMenuItem
OpenMenuItem
FileMenuItem<abstract>
SaveMenuItem
ActionListener<interfaccia>
FindMenuItem
JMenuItem
QuitMenuItem
EditorMenuItem/** EditorMenuItem: un menu item generico */
abstract class EditorMenuItem extends JMenuItem implements ActionListener
{ // il buffer su cui opera il menu item private EditBuffer buffer;
public EditorMenuItem(String label, EditBuffer buff) { super(label);buffer = buff;addActionListener(this);
}
protected EditBuffer getBuffer() { return buffer; }
// no actionPerformed(): la classe e` abstract}
Clear/Cut/Copy/Paste
class ClearMenuItem extends EditorMenuItem { public ClearMenuItem(String label, EditBuffer buff) { super(label, buff); }
public void actionPerformed(ActionEvent e) { getBuffer().clear(); }}
class CutMenuItem extends EditorMenuItem { public CutMenuItem(String label, EditBuffer buff) { super(label, buff); }
public void actionPerformed(ActionEvent e) { getBuffer().cut(); }}
Continua…
Clear/Cut/Copy/Paste
class CopyMenuItem extends EditorMenuItem { public CopyMenuItem(String label, EditBuffer buff) { super(label, buff); }
public void actionPerformed(ActionEvent e) { getBuffer().copy(); }}
class PasteMenuItem extends EditorMenuItem { public PasteMenuItem(String label, EditBuffer buff) { super(label, buff); } public void actionPerformed(ActionEvent e) { getBuffer().paste(); }}
Find
/** * FindMenuItem: genera un dialog per cercare * una stringa nella text area */
class FindMenuItem extends EditorMenuItem { public FindMenuItem(String label, EditBuffer buff) { super(label, buff); } // . . . metodo actionPerformed . . .
}
Continua…
Find
public void actionPerformed(ActionEvent e) { String s = JOptionPane.showInputDialog(this,"Search:"); if ( s != null ) { int index = buffer.findFromCaret(s);
if ( index == -1 ) { int response = JOptionPane.showConfirmDialog(this,
"Not found. Wrapped Search?"); if ( response == JOptionPane.YES_OPTION ) { index = buffer.findFromStart(s); if ( index == -1 ) JOptionPane.showMessageDialog(thi "Not Found"); }
} }
Quit
/** QuitMenuItem: esci dall'editor */
class QuitMenuItem extends JMenuItem implements ActionListener{ private EditFrame frame; public QuitMenuItem(String label, EditFrame frame) {
super(label);this.frame = frame; addActionListener(this);
}
public void actionPerformed(ActionEvent e) {if (frame.confirmQuit()) System.exit(0); return;
}}
FileMenuItem
abstract class FileMenuItem extends EditorMenuItem {
public FileMenuItem(String label, EditBuffer buff) {super(label, buff);
}
public File chooseFile() { File chosen = null; JFileChooser chooser = new JFileChooser();chooser.setDialogTitle("Open");int result = chooser.showDialog(null,“Open");if ( result == JFileChooser.APPROVE_OPTION ) { chosen = chooser.getSelectedFile();}return chosen;
}}
JFileChooser
Openclass OpenMenuItem extends FileMenuItem { public OpenMenuItem(String label, EditBuffer buff) {
super(label, buff); } public void actionPerformed(ActionEvent e) {
File f = chooseFile(); if ( f == null) return;getBuffer().setFile(f); try { getBuffer().setText(""); getBuffer().openFile(); } catch (IOException exc) { JOptionPane.showMessageDialog(null,
"Could not open File");}
}}
EditBufferpublic class EditBuffer extends JTextArea{ private File f; // il file associato al buffer
public EditBuffer(File initFile, int rows, int cols) { super("", rows, cols); f = initFile; setLineWrap(true); setFont(new Font("Courier", Font.PLAIN, 14));
if (f == null) return; try {
openFile(); } catch (IOException e) { JOptionPane.showMessageDialog(this,"File not Found!"); } } . . . Continua…
EditBuffer
public void openFile() throws IOException { Scanner opened = null; try { FileReader r = new FileReader(f); opened = new Scanner(r); while ( opened.hasNextLine() ) {
String s = opened.nextLine(); append(s+"\n");
}} finally { if (opened != null) opened.close(); }
}
Continua…
EditBuffer
public void saveBuffer() throws IOException, NoFileSelectedException {
PrintWriter p = null;if (f == null) throw new NoFileSelectedException(); try { FileWriter w = new FileWriter(f); p = new PrintWriter(w); p.print(getText()); } finally { if (p != null) p.close();}
}