"Hej! I dagens lektion vil vi fortsætte vores samtale om input- og outputstrømme i Java ( Java I/O ). Dette er ikke den første lektion om dette emne, og det bliver bestemt ikke den sidste :)
Da det sker, giver Java-sproget mange måder at arbejde med I/O på. Der er en del klasser, der implementerer denne funktionalitet, så vi har delt dem op i flere lektioner — så du ikke bliver forvirret fra starten :) Tidligere lektioner, vi kom ind på
Sådan ser det ud at læse data fra en fil ved hjælp af

BufferedReader
, samt de InputStream
abstrakte OutputStream
klasser og flere efterkommere. I dag vil vi overveje 3 nye klasser: FileInputStream
, FileOutputStream
, og BufferedInputStream
.
FileOutputStream-klassen
Hovedformålet medFileOutputStream
klassen er at skrive bytes til en fil. Intet kompliceret :) FileOutputStream
er en af implementeringerne af den OutputStream
abstrakte klasse. I konstruktøren tager objekter af denne klasse enten stien til målfilen (hvor bytes skal skrives) eller et File
objekt. Vi vil undersøge 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 oprettede File
objektet, sendte vi den ønskede sti til konstruktøren. Vi behøver ikke oprette det på forhånd: hvis det ikke findes, vil programmet oprette det. Du kan også klare dig uden at oprette et ekstra objekt, blot sende en streng med stien:
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 vil i begge tilfælde være det samme. Vi kan åbne vores fil og se følgende der:
Hi! Welcome to CodeGym — The best site for would-be programmers!
Men der er en nuance her. Prøv at køre koden fra eksemplet ovenfor flere gange i træk. Så kig i filen og svar på dette spørgsmål: hvor mange linjer har den? Bare en. Men du kørte koden flere gange. Det viser sig, at dataene overskrives hver gang - de gamle erstattes af de nye. Hvad gør vi, hvis det ikke passer os, og vi skal skrive sekventielt til filen? Hvad hvis vi vil skrive vores hilsen til en fil tre gange i træk? Det hele er meget enkelt. Da sproget ikke kan vide, hvilken adfærd vi har brug for i hvert enkelt tilfælde, FileOutputStream
kan konstruktøren tage en ekstra parameter —boolean append
. Hvis værdien er sand, vil dataene blive skrevet til slutningen af filen. Hvis det er falsk (og som standard er det falsk), vil alle gamle data blive slettet og erstattet af nye data. Lad os tjekke dette ved at køre vores ændrede kode tre gange:
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();
}
}
Filens indhold:
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!
Nu er det anderledes! Glem ikke denne funktion, når du bruger I/O-klasser. Der var engang, hvor jeg brugte timevis på opgaver, slyngede mine hjerner i timevis, prøvede at forstå, hvordan mine data forsvandt fra filer :) Og selvfølgelig, ligesom med andre I/O-klasser, glem ikke at bruge close()
metoden at frigøre ressourcer.
FileInputStream-klassen
DenFileInputStream
har det modsatte formål - at læse bytes fra en fil. Ligesom FileOutputStream
arver OutputStream
stammer denne klasse fra den InputStream
abstrakte klasse. Vi skriver et par linjer tekst i vores " test.txt " fil:
"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 læser en byte fra filen, konverterer de læste bytes til tegn og viser dem på konsollen. Og her er konsoludgangen:
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, givet viden fra tidligere lektioner, at du nemt kan sige, hvorfor vi har brug for klassen,BufferedInputStream
og hvilke fordele den har i forhold til FileInputStream
:) Vi har allerede stødt på buffer-streams, så prøv at gætte (eller husk), før du fortsætter med at læse :) Bufret streams er primært nødvendige for at optimere I/O. Adgang til en datakilde, såsom at læse fra en fil, er en dyr operation med hensyn til ydeevne, og det er spild at få adgang til en fil for at læse hver byte. Derfor BufferedInputStream
læser data ikke én byte ad gangen, men i blokke og gemmer dem midlertidigt i en speciel buffer. Dette lader os optimere programmet ved at reducere antallet af gange, vi får adgang til filen. Lad os se, hvordan dette ser ud:
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 lavede vi et BufferedInputStream
objekt. Dens konstruktør tager en forekomst af InputStream
klassen eller nogen af dens efterkommere, det FileInputStream
vil også gøre det. Som et yderligere argument tager det bufferstørrelsen i bytes. Takket være dette argument vil dataene nu blive læst fra filen ikke én byte ad gangen, men 200 bytes ad gangen! Forestil dig, hvor meget vi har reduceret antallet af filadgange. For at sammenligne ydeevne kan du tage en stor tekstfil (adskillige megabyte tekst) og sammenligne, hvor lang tid det tager i millisekunder at læse og udlæse til konsollen ved hjælp af FileInputStream
og BufferedInputStream
. Her er kode, der viser begge muligheder:
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 læste en 1,5 MB fil på min computer, FileInputStream
fuldførte arbejdet på ~3500 millisekunder, men BufferedInputStream
klarede det på ~1700 millisekunder. Som du kan se, optimerede den bufrede strøm arbejdet og halverede det! :) Vi vil fortsætte med at studere I/O-klasser — vi ses snart!
GO TO FULL VERSION