"Hei! I dagens leksjon vil vi fortsette samtalen vår om inn- og utdatastrømmer i Java ( Java I/O ). Dette er ikke den første leksjonen om dette emnet, og det vil absolutt ikke være den siste :)
Som det skjer, gir Java-språket mange måter å jobbe med I/O på. Det er ganske mange klasser som implementerer denne funksjonaliteten, så vi har delt dem inn i flere leksjoner — slik at du ikke blir forvirret fra starten av :) Tidligere leksjoner kom vi inn på
Slik ser det ut å lese data fra en fil ved hjelp av

BufferedReader
, samt InputStream
abstrakte OutputStream
klasser og flere etterkommere. I dag skal vi vurdere 3 nye klasser: FileInputStream
, FileOutputStream
, og BufferedInputStream
.
FileOutputStream-klassen
Hovedformålet medFileOutputStream
klassen er å skrive bytes til en fil. Ikke noe komplisert :) FileOutputStream
er en av implementeringene av den OutputStream
abstrakte klassen. I konstruktøren tar objekter av denne klassen enten banen til målfilen (hvor bytene skal skrives) eller et File
objekt. Vi vil undersøke eksempler på hver:
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();
}
}
Da vi opprettet File
objektet, ga vi den ønskede banen til konstruktøren. Vi trenger ikke lage den på forhånd: hvis den ikke eksisterer, vil programmet lage den. Du kan også klare deg uten å lage et ekstra objekt, bare passere en streng med banen:
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();
}
}
Resultatet i begge tilfeller vil være det samme. Vi kan åpne filen vår og se følgende der:
Hi! Welcome to CodeGym — The best site for would-be programmers!
Men det er en nyanse her. Prøv å kjøre koden fra eksemplet ovenfor flere ganger på rad. Se så i filen og svar på dette spørsmålet: hvor mange linjer har den? Bare én. Men du kjørte koden flere ganger. Det viser seg at dataene blir overskrevet hver gang - de gamle erstattes av de nye. Hva gjør vi hvis det ikke passer oss og vi må skrive sekvensielt til filen? Hva om vi vil skrive en hilsen til en fil tre ganger på rad? Det hele er veldig enkelt. Siden språket ikke kan vite hvilken oppførsel vi trenger i hvert enkelt tilfelle, FileOutputStream
kan konstruktøren ta en ekstra parameter -boolean append
. Hvis verdien er sann, vil dataene bli skrevet til slutten av filen. Hvis det er usant (og som standard er det usann), vil alle gamle data bli slettet og erstattet av nye data. La oss sjekke dette ved å kjøre vår modifiserte kode tre ganger:
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();
}
}
Filinnhold:
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!
Nå er det annerledes! Ikke glem denne funksjonen når du bruker I/O-klasser. Det var en gang da jeg brukte timer på oppgaver, maset hjernen i timevis, prøvde å forstå hvordan dataene mine forsvant fra filene :) Og selvfølgelig, akkurat som med andre I/O-klasser, ikke glem å bruke close()
metoden å frigjøre ressurser.
FileInputStream-klassen
DenFileInputStream
har det motsatte formålet - å lese bytes fra en fil. På samme måte som FileOutputStream
arver OutputStream
, stammer denne klassen fra den InputStream
abstrakte klassen. Vi skriver noen få linjer med tekst i " test.txt "-filen vår:
"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);
}
}
}
Vi leser én byte fra filen, konverterer de leste bytene til tegn og viser dem på konsollen. Og her er konsollutgangen:
So close no matter how far
Couldn't be much more from the heart
Forever trusting who we are
And nothing else matters
BufferedInputStream-klassen
Jeg tror, gitt kunnskapen fra tidligere leksjoner, kan du enkelt si hvorfor vi trenger klassenBufferedInputStream
og hvilke fordeler den har sammenlignet med FileInputStream
:) Vi har allerede møtt bufrede strømmer, så prøv å gjette (eller husk) før du fortsetter å lese :) Bufret strømmer er hovedsakelig nødvendig for å optimalisere I/O. Å få tilgang til en datakilde, for eksempel å lese fra en fil, er en kostbar operasjon når det gjelder ytelse, og å få tilgang til en fil for å lese hver byte er bortkastet. Derfor BufferedInputStream
leser data ikke én byte om gangen, men i blokker, og lagrer dem midlertidig i en spesiell buffer. Dette lar oss optimere programmet ved å redusere antall ganger vi får tilgang til filen. La oss se hvordan dette ser ut:
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);
}
}
}
Her har vi laget et BufferedInputStream
objekt. Konstruktøren tar en forekomst av InputStream
klassen eller noen av dens etterkommere, det FileInputStream
vil også gjøre. Som et ekstra argument tar den bufferstørrelsen i byte. Takket være dette argumentet vil dataene nå leses fra filen, ikke én byte om gangen, men 200 byte om gangen! Tenk deg hvor mye vi har redusert antall filtilganger. For å sammenligne ytelse kan du ta en stor tekstfil (flere megabyte med tekst) og sammenligne hvor lang tid det tar i millisekunder å lese og sende ut til konsollen ved å bruke FileInputStream
og BufferedInputStream
. Her er koden som viser begge alternativene:
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()));
}
}
Når jeg leste en 1,5 MB fil på datamaskinen min, FileInputStream
fullførte arbeidet på ~3500 millisekunder, men BufferedInputStream
klarte det på ~1700 millisekunder. Som du kan se, optimaliserte den bufrede strømmen arbeidet, og kuttet det i to! :) Vi vil fortsette å studere I/O-klasser — ses snart!
GO TO FULL VERSION