Lezione 14 Lettura e scrittura di file Programmazione per la Musica | Prof. Luca A. Ludovico Leggere e scrivere file in Java • Obiettivo della lezione è saper aprire in lettura e scrittura file binari. • Possibili applicazioni: import/export di contenuti musicali rispetto a strutture dati interne, salvataggio della configurazione, interfacciamento con altri sistemi, … • Il primo passaggio è istanziare un oggetto della classe File, dopodiché è possibile istanziare un oggetto della classe BufferedReader che prende questo file come argomento in ingresso. Programmazione per la Musica - Prof. Luca A. Ludovico 14. Lettura e scrittura di file La classe File • La classe File fornisce una rappresentazione astratta del percorso (pathname) di una cartella (directory) o di un documento (file). • Sistemi operativi e interfacce utilizzano stringhe dipendenti dal sistema in uso. Questa classe mette a disposizione un’astrazione comunque gerarchica ma indipendente dal sistema. • Esempio: nei percorsi si usa il separatore “/” in Unix, ma Windows ammette anche “\” Programmazione per la Musica - Prof. Luca A. Ludovico 14. Lettura e scrittura di file La classe File • Un percorso può essere assoluto o relativo. Quando è assoluto, contiene intrinsecamente tutte le informazioni per localizzare un file. Se invece è relativo, deve essere interpretato sulla base di altre informazioni. • Di default, le classi nel package java.io risolvono i percorsi relativi rispetto alla directory corrente. Tipicamente, si tratta della cartella in cui si invoca la Java Virtual Machine. – In NetBeans, il path relative fa riferimento alla cartella del progetto, ad esempio JavaApplication1. Programmazione per la Musica - Prof. Luca A. Ludovico 14. Lettura e scrittura di file Costruttori e metodi della classe File • Costruttori: File(String pathname), File(URI uri), … • boolean canExecute() • boolean canRead() • boolean canWrite() testano i permessi da parte dell’applicazione • boolean delete() • void deleteOnExit() cancellano il file o la cartella, istantaneamente o alla chiusura della virtual machine Programmazione per la Musica - Prof. Luca A. Ludovico 14. Lettura e scrittura di file Verifica dell’esistenza • Nella lettura di file, la principale problematica da gestire è il fatto che si tratti realmente di un file. • Il modo più semplice è invocare il metodo boolean isFile(), ed esiste anche boolean isDirectory() • In alternativa, il metodo boolean File.exists() verifica se il file o la directory esistono. Programmazione per la Musica - Prof. Luca A. Ludovico 14. Lettura e scrittura di file Altri metodi della classe File • La classe File mette a disposizione un gran numero di metodi per gestire documenti e cartelle. Ad esempio: – String getName() restituisce il nome del file o directory – String getParent() dà il nome della cartella padre – String getPath() converte il nome astratto in un percorso a stringa – boolean isHidden() verifica se si tratta di file nascosto – long lastModified() restituisce l’istante di ultima modifica – long length() dà la dimensione del file – String[] list() dà l’elenco di file e cartelle contenute nella cartella denotata dal path corrente (con numerose varianti…) – … Programmazione per la Musica - Prof. Luca A. Ludovico 14. Lettura e scrittura di file La classe FileReader • FileReader è pensata per leggere del testo carattere per carattere. • Costruttori: FileReader(File file), FileReader(String fileName), … Programmazione per la Musica - Prof. Luca A. Ludovico 14. Lettura e scrittura di file La classe BufferedReader • Un BufferedReader legge testo da un flusso di caratteri in ingresso, in modo da rendere efficiente la lettura sequenziale di caratteri e righe • Sarebbe possibile specificare anche la dimensione del buffer, ma quella di default è sufficientemente capiente per la maggior parte delle applicazioni • Tra i principali metodi: int read() legge un singolo carattere, String readLine() legge una riga di testo e long skip(long n) salta nella lettura un certo numero di caratteri Programmazione per la Musica - Prof. Luca A. Ludovico 14. Lettura e scrittura di file Lettura di un file riga per riga File file = new File("miofile.txt"); if (file.isFile()) { try { FileReader fileReader = new FileReader (file) BufferedReader bufReader = new BufferedReader(fileReader); String line; // lettura del file di testo riga per riga while ((line = bufReader.readLine()) != null) { ; // operazioni su line } bufReader.close(); // rilascio delle risorse } catch (IOException e) { } } Programmazione per la Musica - Prof. Luca A. Ludovico 14. Lettura e scrittura di file ESEMPIO ParseLines.java Il software carica da un file in formato TXT diversi modelli di scala, codificati uno per riga nella forma nome_modello1/pc,nc;pc,nc;… nome_modello2/pc,nc;pc,nc;… e dopo averli caricati all’interno di opportune strutture dati li visualizza nella console. Programmazione per la Musica - Prof. Luca A. Ludovico 14. Lettura e scrittura di file La classe StringTokenizer • Negli esempi visti in precedenza si è spesso utilizzato il metodo String[] split(String regex), ove regex è un’espressione regolare. • Una valida alternativa è costituita dalla classe StringTokenizer del package java.util, che fornisce metodi per spezzare una stringa in token. Un token è una sequenza massimale di caratteri che non contiene un delimitatore. – Ad esempio, è possibile leggere una frase in input e considerare lo spazio come delimitatore dei token, in modo da ottenere un array di singole parole. Programmazione per la Musica - Prof. Luca A. Ludovico 14. Lettura e scrittura di file Costruttori • Un’istanza di StringTokenizer viene creata indicando: – la stringa da spezzare, – l'eventuale insieme di delimitatori (per default " \t\n\r\f") – se i delimitatori sono token o no • StringTokenizer (String str, String delim, boolean returnDelims) Crea un tokenizer per 'str', che usa i caratteri in 'delim', come delimitatori. 'returnDelims' indica se restituire i delimitatori come token oppure scartarli. • StringTokenizer (String str, String delim) Come sopra, con returnDelims == false • StringTokenizer (String str) Come sopra, con delim == " \t\n\r\f" Programmazione per la Musica - Prof. Luca A. Ludovico 14. Lettura e scrittura di file Principali metodi • Un’istanza di StringTokenizer scorre la stringa sequenzialmente dall'inizio alla fine, restituendo i token uno alla volta. I metodi principali sono: • boolean hasMoreTokens() restituisce true se c'e' ancora un token da restituire • String nextToken() restituisce il prossimo token • String nextToken(String delim) restituisce il prossimo token, usando i caratteri di 'delim' come delimitatori • int countTokens() restituisce il numero di token che restano da esaminare Programmazione per la Musica - Prof. Luca A. Ludovico 14. Lettura e scrittura di file ESEMPIO EasyScore.java Il software interpreta una rappresentazione testuale di una partitura, in cui ogni riga corrisponde a uno strumento (monodico) e ogni gruppo di caratteri separato da virgole a una pulsazione di valore ritmico predefinito (ad esempio da un ottavo). Le altezze sono scritte in notazione anglosassone (ad es. C4 rappresenta il Do della quarta ottava, e Eb5 il Mi bemolle della quinta). Le pause sono contrassegnate come note «degeneri» tramite la lettera R. E’ possibile introdurre spazi per allineare le note dal punto di vista grafico, ma questi devono essere stralciati dal parsing della melodia. Le durate si ricavano dal numero di virgole che separano le stringhe. Ad esempio, l’incipit di Fra’ Martino sarebbe: C4,D4,E4,C4,C4,D4,E4,C4,E4,F4,G4, ,E4,F4,G4, ,G4, ,G4 R, , , , , , , ,C4,D4,E4,C4,C4,D4,E4,C4,E4,F4,G4 Si utilizzi la classe StringTokenizer. Programmazione per la Musica - Prof. Luca A. Ludovico 14. Lettura e scrittura di file Scrittura di file su disco • Si può scrivere su file usando due modalità: carattere per carattere e per stringhe, in analogia con le tecniche di lettura da file. • FileWriter scrive singoli caratteri • BufferedWriter scrive intere stringhe • Il comportamento è molto simile, dato che FileWriter eredita i metodi di scrittura dalla superclasse: java.io.OutputStreamWriter Programmazione per la Musica - Prof. Luca A. Ludovico 14. Lettura e scrittura di file Esempio di scrittura con FileWriter import java.io.*; class ScriviPitches { public static void main(String args[]) throws IOException { FileWriter w; w = new FileWriter("pitches.txt"); w.write('A'); // carattere per carattere w.write('G'); w.flush(); // scarica su file } } Programmazione per la Musica - Prof. Luca A. Ludovico 14. Lettura e scrittura di file Esempio di scrittura con BufferedWriter import java.io.*; class ScriviPitches { public static void main(String args[]) throws IOException { FileWriter w; w = new FileWriter("pitches.txt"); BufferedWriter b; b = new BufferedWriter (w); b.write("Do Re Mi\nFa Sol La"); b.write("Si"); b.flush(); } } Programmazione per la Musica - Prof. Luca A. Ludovico 14. Lettura e scrittura di file ESERCIZIO Data una struttura dati che contiene un ArrayList di note (ciascuna caratterizzata da nome della nota, ottava, stato di alterazione, durata) si trovi il modo per scrivere queste informazioni separatamente allineandole in colonna: • Prima riga: nomi delle note • Seconda riga: stato di alterazione • Terza riga: ottava • Quarta riga: numeratore • Quinta riga: denominatore Programmazione per la Musica - Prof. Luca A. Ludovico 14. Lettura e scrittura di file