/* *************************************************************************
* Ora parleremo dell'I/O, ossia Input/Output (Entrata/Uscita).
* Il sistema I/O del Java ha un'interfaccia indipendente dall'hardware,
* analoga a quella UNIX del C, che pone un certo livello di astrazione tra
* il programmatore e il dispositivo in uso, per cui e' analogo accedere a
* terminali connessi in rete, unita' a disco, a nastro, eccetera.
* I diversi dispositivi sono considerati un dispositivo logico chiamato
* FLUSSO (detto stream o pipe). I flussi partono da una sorgente ed arrivano
* ad una destinazione, astraendosi dai dispositifi fisici che lo permettono.
* I tipi di flusso in UNIX/ANSI C sono 2:
*
* 1) FLUSSO DI TESTO: e' una sequenza di caratteri, che pero' durante il
* trasferimento puo' subire anche delle conversioni secondo le necessita'
* dell'ambiente di destinazione (ad esempio il carattere di fine riga e'
* diverso in certi casi: puo' essere di newline o cr+lf) il che implica
* che il flusso eventualmente convertito puo' essere anche di dimensione
* diversa. Passando un file non di testo da questo flusso si danneggia!
*
* 2) FLUSSO BINARIO: e' una sequenza di byte avente una corrispondenza uno
* a uno con la sequenza rivevuta dal dispositivo esterno. Non avvenendo
* alcuna conversione il numero di byte scritti/letti rimane uguale.
*
* In java sono disponibili anche flussi filtrati piu' sofisticati.
* Abbiamo gia' visto comandi per I/O da e verso la console (tastiera/video).
* Ora vedremo il caso di lettura/scrittura di file.
* In Java le superclassi da cui sono derivati i vari flussi particolari
* sono InputStream e OutputStream. Le subclassi che ci interessano sono
* FileInputStream e FileOutputStream, dedicate al flusso di file.
* Ad esempio:
*
* FileInputStream MioInFilStr = new FileInputStream("Jlez6a.java");
* FileOutputStream MioOutFilStr = new FileOutputStream("Jlez6a.bak");
*
* Queste classi pero' hanno metodi che possono leggere e scrivere soltanto
* bytes, e non altri tipi di dati. Se si desiderano leggere/scrivere degli
* int, dei float, o altri dati, si puo' convertire/filtrare lo stream usando
* delle classi come DataInputStream:
*
* DataInputStream MioInDatStr = new DataInputStream(MioInFilStr);
* DataOutputStream MioOutDatStr = new DataOutputStream(MioOutFilStr);
*
* A questo punto saranno disponibili dei metodi piu sofisticati: readChar(),
* readBoolean(), readFloat(), readLine(); writeChar(), writeFloat(), ecc.
* Comunque, per maggiore semplicita', leggeremo e scriveremo bytes, usando
* direttamente InputStream e OutputStream, per creare una copia di questo
* file sorgente (Jlez6a.java) chiamata Jlez6a.bak.
* Le eccezioni generate da queste classi sono di tipo IOException:
*
* try {
* MioInFilStr = new FileInputStream("Jlez6a.java");
* }
* catch (IOException e) {
* System.out.println("Errore: " + e + " nella lettura di un file");
* System.exit(0);
* }
*
* Attenzione che si scrive su HD, io vi ho avvertito!
************************************************************************* */
import java.io.*; // Include le funzioni I/O standard di base.
class Jlez6a { // Da qua inizia la classe Jlez6a
public static void main(String args[]) // Definiamo il metodo Main.
{ // Inizio del main()
// Gli input/output stream e la variabile LungFile li dichiaro nel main(),
// in modo che siano accessibili ovunque. Se fossero dichiarati all'interno
// di un blocco { } di un try o del for, all'esterno di tale blocco non
// esisterebbero. Fate attenzione a questo fatto quando decidete dove
// dichiarare variabili/oggetti! Dichiarateli localmente solo se sono
// effettivamente usati esclusivamente all'interno del blocco. Per esempio
// la variabile i usata nel for e' dichiarata (e usabile) solo nel blocco
// del for, perche' effettivamente non viene usata mai fuori da esso.
FileInputStream MioInFilStr = null;
FileOutputStream MioOutFilStr = null;
int LungFile = 0;
// Provo ad aprire il file Jlez6a.java in lettura con FileInputStream.
try {
MioInFilStr = new FileInputStream("Jlez6a.java");
}
catch (IOException e) {
System.out.println("Errore: " + e + " nella lettura di un file");
System.exit(0);
}
// Provo ad aprire/creare Jlez6a.bak in scrittura con FileOutputStream.
try {
MioOutFilStr = new FileOutputStream("Jlez6a.bak");
}
catch (IOException e) {
System.out.println("Errore: " + e + " nella creazione di un file");
System.exit(0);
}
// Se sono arrivato qua senza eccezioni, ho i 2 flussi (stream) attivi.
// Per creare il file di copia bastera' leggere dalla sorgente e scrivere
// nella destinazione tutti i bytes, uno alla volta.
// Per sapere quanti byte posso copiare (cioe' la lunghezza del file) uso
// il metodo int available().
try {
LungFile = MioInFilStr.available(); // Mi informo sul num. bytes.
}
catch (IOException e) {
System.out.println("Errore: " + e + " determinando la lungh. di un file");
System.exit(0);
}
// Per leggere/scrivere uso FileInputStream.read(), FileOutPutStream.write().
// So quanti bytes devo copiare, grazie ad available().
try {
for(int i=0; i<LungFile; i++) {
MioOutFilStr.write(MioInFilStr.read()); // copio un byte.
}
}
catch (IOException e) {
System.out.println("Errore: " + e + " nella copia di un file");
System.exit(0);
}
// File copiato, posso chiudere i due flussi (stream).
try {
MioInFilStr.close(); // Chiudo l'InputStream.
MioOutFilStr.close(); // Chiudo l'OutputStream.
}
catch (IOException e) {
System.out.println("Errore: " + e + " nella chiusura di un file");
System.exit(0);
}
// Scriviamo un messaggio di felicitazioni
System.out.print("File copiato, " + LungFile + " bytes,");
System.out.println(" suffisso copia: .bak");
} // Fine del metodo principale Main()
} // Fine della classe Jlez6a
