"Ciao! Nella lezione di oggi, continueremo la nostra conversazione sui flussi di input e output in Java ( Java I/O ). Questa non è la prima lezione su questo argomento, e certamente non sarà l'ultima :)
Poiché accade, il linguaggio Java offre molti modi per lavorare con l'I / O. Ci sono alcune classi che implementano questa funzionalità, quindi le abbiamo divise in diverse lezioni, quindi non ti confonderai dall'inizio :) In passato lezioni, abbiamo toccato
Ecco come appare leggere i dati da un file usando

BufferedReader
, così come le InputStream
e OutputStream
classi astratte e diversi discendenti.Oggi considereremo 3 nuove classi: FileInputStream
, FileOutputStream
, e BufferedInputStream
.
La classe FileOutputStream
Lo scopo principale dellaFileOutputStream
classe è scrivere byte in un file. Niente di complicato :) FileOutputStream
è una delle implementazioni della OutputStream
classe astratta. Nel costruttore, gli oggetti di questa classe prendono il percorso del file di destinazione (dove dovrebbero essere scritti i byte) o un File
oggetto. Esamineremo esempi di ciascuno:
public class Main {
public static void main(String[] args) throws IOException {
File file = new File("C:\\Users\\Username\\Desktop\\test.txt");
FileOutputStream fileOutputStream = new FileOutputStream(file);
String greetings = "Hi! Welcome to CodeGym — The best site for would-be programmers!";
fileOutputStream.write(greetings.getBytes());
fileOutputStream.close();
}
}
Durante la creazione dell'oggetto File
, abbiamo passato il percorso desiderato al costruttore. Non abbiamo bisogno di crearlo in anticipo: se non esiste, il programma lo creerà. Puoi anche cavartela senza creare un oggetto extra, semplicemente passando una stringa con il percorso:
public class Main {
public static void main(String[] args) throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Username\\Desktop\\test.txt");
String greetings = "Hi! Welcome to CodeGym — The best site for would-be programmers!";
fileOutputStream.write(greetings.getBytes());
fileOutputStream.close();
}
}
Il risultato in entrambi i casi sarà lo stesso. Possiamo aprire il nostro file e vedere quanto segue:
Hi! Welcome to CodeGym — The best site for would-be programmers!
Ma c'è una sfumatura qui. Prova a eseguire il codice dell'esempio precedente più volte di seguito. Quindi guarda nel file e rispondi a questa domanda: quante righe ha? Solo uno. Ma hai eseguito il codice diverse volte. Si scopre che i dati vengono sovrascritti ogni volta: il vecchio viene sostituito dal nuovo. Cosa facciamo se non ci va bene e dobbiamo scrivere in sequenza sul file? E se volessimo scrivere il nostro saluto su un file tre volte di seguito? È tutto molto semplice. Dal momento che la lingua non può sapere di quale comportamento abbiamo bisogno in ogni caso, il FileOutputStream
contrucutor può prendere un parametro aggiuntivo —boolean append
. Se il suo valore è true, i dati verranno scritti alla fine del file. Se è falso (e per impostazione predefinita è falso), tutti i vecchi dati verranno cancellati e sostituiti da nuovi dati. Controlliamo questo eseguendo il nostro codice modificato tre volte:
public class Main {
public static void main(String[] args) throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Username\\Desktop\\test.txt", true);
String greetings = "Hi! Welcome to CodeGym — The best site for would-be programmers!\r\n";
fileOutputStream.write(greetings.getBytes());
fileOutputStream.close();
}
}
Contenuto dell'archivio:
Hi! Welcome to CodeGym — The best site for would-be programmers!
Hi! Welcome to CodeGym — The best site for would-be programmers!
Hi! Welcome to CodeGym — The best site for would-be programmers!
Ora è diverso! Non dimenticare questa funzione quando usi le classi I/O. C'è stato un tempo in cui passavo ore in attività, a scervellarmi per ore, cercando di capire come i miei dati stavano scomparendo dai file :) E ovviamente, proprio come con altre classi di I/O, non dimenticare di usare il close()
metodo per liberare risorse.
La classe FileInputStream
haFileInputStream
lo scopo opposto: leggere byte da un file. Proprio come FileOutputStream
inherits OutputStream
, questa classe deriva dalla InputStream
classe astratta. Scriveremo alcune righe di testo nel nostro file " test.txt ":
"So close no matter how far
Couldn't be much more from the heart
Forever trusting who we are
And nothing else matters"

FileInputStream
:
public class Main {
public static void main(String[] args) throws IOException {
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\test.txt");
int i;
while((i=fileInputStream.read())!= -1){
System.out.print((char)i);
}
}
}
Leggiamo un byte dal file, convertiamo i byte letti in caratteri e li visualizziamo sulla console. Ed ecco l'output della console:
So close no matter how far
Couldn't be much more from the heart
Forever trusting who we are
And nothing else matters
La classe BufferedInputStream
Penso che, data la conoscenza delle lezioni precedenti, puoi facilmente dire perché abbiamo bisogno dellaBufferedInputStream
classe e quali vantaggi ha rispetto a FileInputStream
:) Abbiamo già incontrato flussi bufferizzati, quindi prova a indovinare (o ricordare) prima di continuare a leggere :) I flussi bufferizzati sono necessari principalmente per ottimizzare l'I/O. L'accesso a un'origine dati, come la lettura da un file, è un'operazione costosa in termini di prestazioni e accedere a un file per leggere ogni byte è uno spreco. Ecco perché BufferedInputStream
legge i dati non un byte alla volta, ma in blocchi, e li memorizza temporaneamente in un buffer speciale. Questo ci consente di ottimizzare il programma riducendo il numero di volte in cui accediamo al file. Vediamo come appare:
public class Main {
public static void main(String[] args) throws IOException {
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\test.txt");
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream, 200);
int i;
while((i = bufferedInputStream.read())!= -1){
System.out.print((char)i);
}
}
}
Qui abbiamo creato un BufferedInputStream
oggetto. Il suo costruttore accetta un'istanza della InputStream
classe o uno qualsiasi dei suoi discendenti, quindi FileInputStream
lo farà. Come argomento aggiuntivo, accetta la dimensione del buffer in byte. Grazie a questo argomento, i dati verranno ora letti dal file non un byte alla volta, ma 200 byte alla volta! Immagina quanto abbiamo ridotto il numero di accessi ai file. Per confrontare le prestazioni, puoi prendere un file di testo di grandi dimensioni (diversi megabyte di testo) e confrontare il tempo impiegato in millisecondi per la lettura e l'output nella console utilizzando FileInputStream
e BufferedInputStream
. Ecco il codice che dimostra entrambe le opzioni:
public class Main {
public static void main(String[] args) throws IOException {
Date date = new Date();
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\textBook.rtf");
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
int i;
while((i = bufferedInputStream.read())!= -1){
System.out.print((char)i);
}
Date date1 = new Date();
System.out.println((date1.getTime() - date.getTime()));
}
}
public class Main {
public static void main(String[] args) throws IOException {
Date date = new Date();
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\26951280.rtf");
int i;
while((i = fileInputStream.read())!= -1){
System.out.print((char)i);
}
Date date1 = new Date();
System.out.println((date1.getTime() - date.getTime()));
}
}
Durante la lettura di un file da 1,5 MB sul mio computer, FileInputStream
ho completato il lavoro in ~ 3500 millisecondi, ma BufferedInputStream
l'ho gestito in ~ 1700 millisecondi. Come puoi vedere, il flusso bufferizzato ha ottimizzato il lavoro, tagliandolo a metà! :) Continueremo a studiare i corsi di I/O — a presto!
GO TO FULL VERSION