"Sziasztok! A mai leckében a Java bemeneti és kimeneti adatfolyamairól folytatjuk a beszélgetést ( Java I/O ). Nem ez az első lecke ebben a témában, és biztosan nem is az utolsó
:) Előfordul, hogy a Java nyelv számos módot biztosít az I/O-val való munkavégzéshez. Jó néhány osztály valósítja meg ezt a funkciót, ezért ezeket több leckére osztottuk – így nem fog összezavarodni a kezdetektől :) leckéket érintettünk
Íme, hogyan néz ki az adatok olvasása egy fájlból a következővel

BufferedReader
, valamint a InputStream
és OutputStream
absztrakt osztályokat és több leszármazottat. Ma 3 új osztályt fogunk figyelembe venni: FileInputStream
, FileOutputStream
, és BufferedInputStream
.
A FileOutputStream osztály
Az osztály fő célja,FileOutputStream
hogy bájtokat írjon egy fájlba. Semmi bonyolult :) FileOutputStream
az absztrakt osztály egyik implementációja OutputStream
. A konstruktorban ennek az osztálynak az objektumai vagy a célfájl elérési útját (ahova a bájtokat kell írni), vagy egy File
objektumot követnek. Megvizsgálunk mindegyikre példákat:
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();
}
}
Az objektum létrehozásakor File
a kívánt útvonalat adtuk át a konstruktornak. Nem kell előre elkészítenünk: ha nem létezik, akkor a program elkészíti. Azt is megteheti, hogy nem hoz létre extra objektumot, egyszerűen átad egy karakterláncot az elérési úttal:
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();
}
}
Az eredmény mindkét esetben ugyanaz lesz. Megnyithatjuk a fájlunkat, és ott a következőket láthatjuk:
Hi! Welcome to CodeGym — The best site for would-be programmers!
De van itt egy árnyalat. Próbálja meg többször egymás után futtatni a fenti példából származó kódot. Ezután nézze meg a fájlt, és válaszoljon erre a kérdésre: hány soros? Csak egy. De többször lefuttatta a kódot. Kiderült, hogy az adatokat minden alkalommal felülírják – a régit felváltja az új. Mit tegyünk, ha ez nem felel meg nekünk, és sorban kell írnunk a fájlba? Mi van akkor, ha háromszor egymás után szeretnénk egy fájlba írni az üdvözletünket? Minden nagyon egyszerű. Mivel a nyelv nem tudhatja, hogy minden esetben milyen viselkedésre van szükségünk, a FileOutputStream
konstruktor további paramétert vehet fel:boolean append
. Ha az értéke igaz, az adatok a fájl végére íródnak. Ha hamis (és alapértelmezés szerint hamis), minden régi adat törlődik, és új adatokkal helyettesítik. Ellenőrizzük ezt úgy, hogy háromszor futtassuk le módosított kódunkat:
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();
}
}
Fájl tartalma:
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!
Ez most más! Ne feledkezzünk meg erről a funkcióról I/O osztályok használatakor. Volt idő, amikor órákat töltöttem feladatokkal, órákig törtem az agyamat, próbáltam megérteni, hogyan tűnnek el az adataim a fájlokból :) És persze, ahogy más I/O osztályoknál, ne felejtsd el használni a close()
módszert források felszabadítására.
A FileInputStream osztály
EnnekFileInputStream
az ellenkezője a célja: bájtok olvasása egy fájlból. Csakúgy, mint FileOutputStream
az öröklődés OutputStream
, ez az osztály az absztrakt osztályból származik InputStream
. Néhány sornyi szöveget írunk a " test.txt " fájlunkba:
"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);
}
}
}
Kiolvasunk egy bájtot a fájlból, az olvasott bájtokat karakterekké alakítjuk és megjelenítjük a konzolon. És íme a konzol kimenete:
So close no matter how far
Couldn't be much more from the heart
Forever trusting who we are
And nothing else matters
A BufferedInputStream osztály
Azt hiszem, a korábbi leckékből szerzett ismeretek alapján könnyen meg tudod mondani, hogy miért van szükségünk azBufferedInputStream
osztályra, és milyen előnyei vannak FileInputStream
:) Már találkoztunk pufferolt adatfolyamokkal, úgyhogy próbálj meg tippelni (vagy emlékezni), mielőtt folytatod az olvasást :) A pufferelt adatfolyamokra elsősorban az I/O optimalizálásához van szükség. Az adatforrás elérése, például egy fájlból való olvasás, költséges művelet a teljesítmény szempontjából, és a fájl elérése az egyes bájtok olvasásához pazarló. Éppen ezért BufferedInputStream
nem bájtonként, hanem blokkokban olvassa be az adatokat, és átmenetileg egy speciális pufferben tárolja. Ez lehetővé teszi a program optimalizálását azáltal, hogy csökkenti a fájl elérésének számát. Nézzük, hogy néz ki ez:
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);
}
}
}
Itt létrehoztunk egy BufferedInputStream
objektumot. A konstruktor egy példányt vesz az InputStream
osztályból vagy bármely leszármazottjából, így FileInputStream
megteszi. További argumentumként a puffer méretét veszi fel bájtokban. Ennek az érvelésnek köszönhetően az adatok mostantól nem egyenként, hanem 200 bájtonként kerülnek kiolvasásra a fájlból! Képzeld el, mennyivel csökkentettük a fájlhozzáférések számát. A teljesítmény összehasonlításához készítsen egy nagy szövegfájlt (több megabájt szöveget), és a és gombokkal hasonlítsa össze, mennyi ideig tart ezredmásodpercben az olvasás és a konzolra való FileInputStream
kimenet BufferedInputStream
. Íme egy kód, amely bemutatja mindkét lehetőséget:
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()));
}
}
Amikor egy 1,5 MB-os fájlt olvastam a számítógépemen, FileInputStream
a munkát ~3500 ezredmásodperc alatt végeztem el, de BufferedInputStream
~1700 ezredmásodperc alatt sikerült. Mint látható, a pufferelt adatfolyam optimalizálta a munkát, félbevágva azt! :) Folytatjuk az I/O osztályok tanulmányozását – hamarosan találkozunk!
GO TO FULL VERSION