Flussi, lettori e scrittori Per sequenze di byte, InputStream, OutputStream e loro sottoclassi. Es: InputStream in = …; int next = in. read(); if (next != -1) byte b = (byte) next; Per sequenze di caratteri, Reader, Writer e loro sottoclassi Es: Reader reader = …; int next = reader. read(); if (next != -1) char c = (char) next; Operazioni di I/O con i File Leggere e scrivere sequenze di byte da file su disco: FileInputStream e FileOutputStream FileInputStream in = new FileInputStream(“input.dat”); Leggere dati di testo da un file su disco: FileReader e FileWriter FileReader reader = new FileReader (“input.txt”); File di Testo La classe BufferedReader con readline() FileReader reader = new FileReader(“inp.txt”); BufferedReader in = new BufferedReader(reader); String inputLine = in.readLine(); double x = Double.parseDouble(inputLine); La classe PrintWriter print e println Alla fine: reader.close() o, per un oggetto writer della classe PrintWriter, writer.close() La gerarchia delle eccezioni • Eccezioni controllate • Eccezioni non controllate Esempio: una classe di prodotti import java.io.BufferedReader; import java.io.EOFException; import java.io.IOException; public class Product { public Product() {...} public Product(String aName, double aPrice, int aScore) {...} public boolean read(BufferedReader in) throws IOException {...} public String getName() {...} public double getPrice() {...} public int getScore() {...} public void setPrice(double newPrice) {...} private String name; private double price; private int score; } Esempio: leggere prodotti da un file di testo public boolean read (BufferedReader in) throws IOException { name = in.readLine(); // legge il nome del prodotto if (name == null) return false; String inputLine = in.readLine(); // legge il prezzo del prodotto if (inputLine == null) throw new EOFException ("EOF durante la lettura del prezzo"); price = Double.parseDouble(inputLine); // legge il punteggio del prodotto inputLine = in.readLine(); if (inputLine == null) throw new EOFException ("EOF durante la lettura del punteggio"); score = Integer.parseInt(inputLine); return true; } Esempio prodotti: gestire le eccezioni public void openFile() { BufferedReader in = null; try {… // mostra la finestra di dialogo di scelta del file in = new BufferedReader (new FileReader(selectedFile)); readProducts(in); } catch(FileNotFoundException e) { JOptionPane.showMessageDialog (null, "Nome del file errato. Prova di nuovo."); } catch(IOException e) { JOptionPane.showMessageDialog (null, "File alterato. Prova di nuovo.");} finally { if (in != null) try { in.close(); } catch(IOException e) { JOptionPane.showMessageDialog (null, "Errore nella chiusura del file.");} } } Esempio prodotti: gestire le eccezioni public void readProducts(BufferedReader in) throws IOException { boolean done = false; while (!done) { Product p = new Product(); if (p.read(in)) panel.addProduct(p); else // ha letto ultimo prodotto done = true; } } Accesso sequenziale e accesso casuale Accesso sequenziale Record a dimensione variabile e a dimensione fissa Programma Database.java import java.io.IOException; import java.io.RandomAccessFile; public class Database { public static void main(String[] args) { ConsoleReader console = new ConsoleReader(System.in); System.out.println (“Inserire il nome del file di dati:"); String filename = console.readLine(); try { RandomAccessFile file = new RandomAccessFile(filename, "rw"); long nrecord = file.length() / RECORD_SIZE; boolean done = false; while (!done) { System.out.println (“Indicare il record da aggiornare (1 - " + nrecord + "), nuovo record (0), uscire (-1)"); int pos = console.readInt(); if (1 <= pos && pos <= nrecord) // aggiorna il record { file.seek((pos - 1) * RECORD_SIZE); Product p = readProduct(file); System.out.println(“Trovato ” + p.getName() + ” ” + p.getPrice() + ” ” + p.getScore()); System.out.println (“Immettere il nuovo prezzo:"); double newPrice = console.readDouble(); p.setPrice(newPrice); file.seek((pos - 1) * RECORD_SIZE); writeProduct(file, p); } else if (pos == 0) // aggiunge un record { System.out.println(“Immettere il nuovo prodotto:"); String name = console.readLine(); System.out.println(“Immettere il prezzo:"); double price = console.readDouble(); System.out.println(“Immettere il punteggio:"); int score = console.readInt(); Product p = new Product(name, price, score); file.seek(nrecord * RECORD_SIZE); writeProduct(file, p); nrecord++; } else if (pos == -1) done = true; } file.close(); } catch(IOException e) { System.out.println(“Eccezione Input/Output ” + e); } } /** Legge una stringa di lunghezza fissa. @param f il file dal quale leggere @param size il numero di caratteri da leggere @return la stringa alla quale sono stati tolti gli spazi eccedenti */ public static String readFixedString(RandomAccessFile f, int size) throws IOException { String b = “"; for (int i = 0; i < size; i++) b += f.readChar(); return b.trim(); } /** Scrive una stringa di lunghezza fissa. @param f il file sul quale scrivere @param size il numero di caratteri da scrivere */ public static void writeFixedString(RandomAccessFile f, String s, int size) throws IOException { if (s.length() <= size) { f.writeChars(s); for (int i = s.length(); i < size; i++) f.writeChar(’ '); } else f.writeChars(s.substring(0, size)); } /** Legge un record di un prodotto. @param f il file dal quale leggere @return il prodotto successivo memorizzato nel file. */ public static Product readProduct(RandomAccessFile { f) throws IOException String name = readFixedString(f, NAME_SIZE); double price = f.readDouble(); int score = f.readInt(); return new Product(name, price, score); } /** Scrive un record di un prodotto. @param f il file sul quale scrivere */ public static void writeProduct(RandomAccessFile f, Product p) throws IOException { writeFixedString(f, p.getName(), NAME_SIZE); f.writeDouble(p.getPrice()); f.writeInt(p.getScore()); } public static final int NAME_SIZE = 30; public static final int CHAR_SIZE = 2; public static final int INT_SIZE = 4; public static final int DOUBLE_SIZE = 8; public static final int RECORD_SIZE = CHAR_SIZE * NAME_SIZE + DOUBLE_SIZE + INT_SIZE; } File di database relazionali Flussi di Oggetti Per scrivere e leggere oggetti possiamo scomporli nelle loro parti elementari e scrivere e leggere queste parti, ma... In Java c’è una soluzione più semplice: le classi ObjectOutputStream e ObjectInputStream In un solo colpo scriviamo o leggiamo interi oggetti! L’Interfaccia Serializable public class Razionale implements Serializable, ... { ... } .... Razionale r = new Razionale(3,5); ObjectOutputStream out = new ObjectOutputStream (new FileOutputStream(“dati.dat”)); out.writeObject (r); o, ancora meglio... Possiamo scrivere (o leggere) in un solo colpo intere collezioni di oggetti: Vector v = new Vector(); String s = Console.readString(); Razionale r = Razionale.parseRaz(s); v.add(r); ObjectOutputStream out = new ObjectOutputStream (new FileOutputStream(“dati.dat”)); out.writeObject (v);