martedì 8 giugno 2010

Java: stream e file

Senza la possibilità di leggere le informazioni utili in un particolare istante e scrivere le stesse per usarle poi in futuro un'applicazione risulterebbe abbastanza limitata. Java introduce il concetto di stream, l'informazione detta prima può giungere sia da un file che da una connessione di rete. Uno stream è un flusso di byte proveniente da una sorgente. In entrambi i casi (input o output) la gestione dell'informazione è essenzialmente la stessa. Sappiamo bene come Java realizzi l'astrazione di ogni cosa mediante l'uso di oggetti, nel caso di stream e file non poteva essere diversamente.
Un oggetto dal quale è possibile leggere una sequenza di byte è detto stream di input, quello nel quale si può invece scrivere (una sequenza di byte) è detto stream di output. Possiamo istanziare oggetti per gli stream dalle classi InputStream e OutputStream. Tutti gli stream orientati ai byte discendono da queste due classi. Un'altra gerarchia di classi viene poi costruita per la gestione degli stream orientati ai caratteri, le classi padri da considerare in tal caso sono le classi (astratte) Reader e Writer.


Avete dato uno sguardo alle gerarchie delle classi per gli stream?
Nella classe InputStream esiste un metodo (astratto) per la lettura di un byte, si tratta del metodo read(). Tale metodo, grazie all'ereditarietà, si trova anche nelle sottoclassi della gerarchia. Colui che crea una nuova classe di stream di input ridefinisce allora il metodo read() per precisare cosa copiare. Per la scrittura di byte viene definito in OutputStream il metodo (astratto) write(). read() e write() sono metodi che possono bloccare il thread che deve leggere o scrivere da uno stream. Ciò permette a Java di mettere da parte il thread in attesa e di eseguire il successivo thread suggerito dallo schedulatore della JVM. Non dimenticate mai di chiudere gli stream aperti durante il programma con il metodo close() che rimette in gioco le risorse fin lì impegnate e svuota il buffer usato dallo stream.
Ad esempio (guardate la figura delle classi), nella classe FileInputStream il metodo read() legge un byte da un file (la classe ridefinisce il metodo per la lettura di byte). Per Java, di default, System.out e System.in sono gli oggetti predefiniti per l'output (su terminale) e l'input (da tastiera).
Quando scriviamo System.out.println("Hello world") stiamo scrivendo su uno stream di output!
Dunque per leggere o scrivere occorre uno stream di input o di output. Con le classi FileInputStream e FileOutputStream è possibile crearne uno dei due. Per associare uno stream a un file si può allora avere qualcosa del genere:

FileInputStream fis=new FileInputStream("myFile.dat");

il file "myFile.dat" verrà cercato nella directory corrente, quella cioè che ospita la classe compilata. L'operazione di prima può essere fatta anche usando un oggetto della classe File:

File f=new File("myFile.dat");
FileInputStream fis=new FileInputStream(f);

Questo è possibile grazie alla presenza di più costruttori della classe FileInputStream. Alcuni dei metodi di questa classe sono:
  • int available(), che ritorna il numero di byte disponibili;
  • void close(), che chiude lo stream e libera le risorse occupate;
  • int read(), che legge i byte dallo stream;
  • long skip(long n), che salta n byte dallo stream di input;
Per la scrittura da uno stream bisogna invece scrivere attraverso gli oggetto della classe FileOutputStream. E' possibile instanzarne uno così:

FileOutputStream fos=new FileOutputStream("myFile.dat");

Anche in questo caso si può passare al costruttore sia il nome completo del path che punta al file sia un oggetto File:

File f=new File("myFile.dat");
FileOutputStream fout=new FileOutputStream(f);

Esiste poi un ulteriore costruttore che prevede oltre al nome del file anche un parametro (booleano) per indicare se scrivere sul file accodando i nuovi byte a quelli già esistenti (append) oppure sovrascrivere il vecchio contenuto con quello nuovo.

FileOutputStream fout=new FileOutputStream("myFile.dat",true);

Alcuni dei metodi più importanti di questa classe sono:
  • void close(), che chiude lo stream e libera le risorse;
  • void write(int b), che scrive il byte sullo stream di output;
La scrittura e la lettura di byte è la forma più elementare delle operazioni di scrittura e lettura. Trattare i byte per poter scrivere file di testo e oggetti in questo modo è alquanto noioso. Ecco perché Java estende le classi di basi ampliando la gerarchia (l'immagine vista prima)!

Nessun commento:

Posta un commento