1. Adatfolyamok

Ritkán létezik egy program önmaga szigeteként. A programok általában valamilyen módon kölcsönhatásba lépnek a „külvilággal”. Ez történhet adatok beolvasásával a billentyűzetről, üzenetek küldésével, oldalak letöltésével az internetről, vagy fordítva, fájlok feltöltésével egy távoli szerverre.

Mindezekre a viselkedésekre egy szóval utalhatunk: adatcsere a program és a külvilág között. Várj, ez nem csak egy szó.

Természetesen maga az adatcsere két részre osztható: adatfogadásra és adatküldésre. Például adatokat olvas be a billentyűzetről egy Scannerobjektum segítségével – ez adatokat fogad. És egy parancs segítségével megjeleníti az adatokat a képernyőn System.out.println()– ez adatküldés.

A programozásban a "folyam" kifejezést az adatcsere leírására használják. Honnan jött ez a kifejezés?

A való életben lehet egy vízfolyásod vagy a tudatfolyamod. A programozásban adatfolyamaink vannak .

A Streams sokoldalú eszköz. Lehetővé teszik a program számára, hogy bárhonnan adatokat fogadjon (bemeneti adatfolyamok), és bárhová küldjön adatokat (output stream). Tehát két típusa van:

  • A bemeneti adatfolyam az adatok fogadására szolgál
  • A kimeneti adatfolyam adatok küldésére szolgál

Az adatfolyamok „kézzelfoghatóvá” tétele érdekében a Java alkotói két osztályt írtak: InputStreamés OutputStream.

Az InputStreamosztálynak van egy read()metódusa, amellyel adatokat olvashat ki belőle. És az OutputStreamosztálynak van egy write()metódusa, amivel adatokat írhatunk rá. Vannak más módszereik is, de erről később.

Bájtfolyamok

Milyen adatokról beszélünk? Milyen formátumba kerül? Más szóval, milyen adattípusokat támogatnak ezek az osztályok?

Ezek általános osztályok, így támogatják a leggyakoribb adattípust - a byte. Egy OutputStreambájtokat (és bájttömböket) írhat, egy InputStreamobjektum pedig bájtokat (vagy bájttömböket) olvashat. Ennyi – nem támogatnak semmilyen más adattípust.

Ennek eredményeként ezeket az adatfolyamokat bájtfolyamoknak is nevezik .

A streamek egyik jellemzője, hogy adataik csak szekvenciálisan olvashatók (vagy írhatók). Nem olvashatsz adatokat egy adatfolyam közepéről anélkül, hogy elolvasnád az előtte lévő összes adatot.

Így működik az adatok olvasása a billentyűzetről az Scannerosztályon keresztül: soronként, soronként olvassa be az adatokat a billentyűzetről. Olvasunk egy sort, majd a következő sort, majd a következő sort, és így tovább. Illetve a sorok olvasásának módszerét nevezzük nextLine().

Az adatok írása OutputStreamis szekvenciálisan történik. Jó példa erre a konzol kimenet. Kiírsz egy sort, amit még egy és még egy követ. Ez egy szekvenciális kimenet. Nem lehet kiírni az első sort, majd a tizedet, majd a másodikat. Minden adat csak szekvenciálisan kerül kiírásra a kimeneti adatfolyamba.

Karakterfolyamok

Nemrég tanulta meg, hogy a karakterláncok a második legnépszerűbb adattípusok, és valóban azok. Sok információ kerül átadásra karakterek és egész karakterláncok formájában. A számítógép kiválóan képes mindent bájtban küldeni és fogadni, de az ember nem ilyen tökéletes.

Ezt a tényt figyelembe véve a Java programozók további két osztályt írtak: Readerés Writer. Az Readerosztály hasonló az InputStreamosztályhoz, de a metódusa read()nem bájtokat olvas, hanem karaktereket ( char). Az Writerosztály megfelel az OutputStreamosztálynak. És akárcsak az Readerosztály, ez is karakterekkel ( char) működik, nem bájtokkal.

Ha ezt a négy osztályt összehasonlítjuk, a következő képet kapjuk:

Bájtok (byte) Karakterek (karakterek)
Adatok olvasása
InputStream
Reader
Adatok írása
OutputStream
Writer

Praktikus alkalmazás

Magukat a InputStream, OutputStream, Readerés Writerosztályokat senki nem használja közvetlenül, mivel nincsenek olyan konkrét objektumokhoz társítva, amelyekből adatokat le lehet olvasni (vagy amibe adatokat lehet írni). De ennek a négy osztálynak rengeteg leszármazottja van, amelyek sok mindenre képesek.


2. InputStreamosztály

Az InputStreamosztály azért érdekes, mert több száz leszármazott osztály szülőosztálya. Nincsenek saját adatai, de vannak olyan metódusai, amelyeket az összes származtatott osztály örököl.

Általában ritkán fordul elő, hogy a stream objektumok belsőleg tároljanak adatokat. A stream egy eszköz az adatok olvasására/írására, de nem tárolására. Mondjuk, vannak kivételek.

InputStreamAz osztály és az összes leszármazott osztály módszerei :

Mód Leírás
int read()
Egy bájtot olvas be az adatfolyamból
int read(byte[] buffer)
Egy bájttömböt olvas be az adatfolyamból
byte[] readAllBytes()
Beolvassa az összes bájtot az adatfolyamból
long skip(long n)
Bájtokat kihagy naz adatfolyamban (elolvassa és eldobja)
int available()
Ellenőrzi, hogy hány bájt maradt az adatfolyamban
void close()
Bezárja a patakot

Nézzük röviden ezeket a módszereket:

read()módszer

A read()metódus beolvas egy bájtot a folyamból, és visszaadja azt. Megzavarhatja a intvisszatérési típus. Ezt a típust választották, mert intez a szabványos egész típus. intA lesz első három bájtja nulla.

read(byte[] buffer)módszer

Ez a read()módszer második változata. Lehetővé teszi, hogy egy bájttömböt InputStreamegyszerre olvasson ki. A bájtokat tároló tömböt argumentumként kell átadni. A metódus egy számot ad vissza – a ténylegesen beolvasott bájtok számát.

Tegyük fel, hogy van egy 10 kilobájtos puffered, és adatokat olvasol egy fájlból az FileInputStreamosztály segítségével. Ha a fájl csak 2 kilobájtot tartalmaz, akkor az összes adat betöltődik a puffertömbbe, és a metódus a 2048 (2 kilobájt) számot adja vissza.

readAllBytes()módszer

Nagyon jó módszer. Csak beolvassa az összes adatot a -tól kezdve, InputStreamamíg el nem fogy, és egy bájtos tömbként adja vissza. Ez nagyon hasznos kis fájlok olvasásához. Előfordulhat, hogy a nagy fájlok fizikailag nem férnek el a memóriában, és a módszer kivételt jelent.

skip(long n)módszer

Ez a módszer lehetővé teszi az első n bájt kihagyását az objektumból InputStream. Mivel az adatok olvasása szigorúan szekvenciálisan történik, ez a módszer egyszerűen beolvassa az első n bájtot az adatfolyamból, és eldobja azokat.

A ténylegesen kihagyott bájtok számát adja eredményül (ha az adatfolyam a nbájtok kihagyása előtt ért véget).

int available()módszer

A metódus az adatfolyamban még hátralévő bájtok számát adja vissza

void close()módszer

A close()metódus bezárja az adatfolyamot, és felszabadítja a hozzá tartozó külső erőforrásokat. Egy adatfolyam bezárása után nem lehet több adatot kiolvasni belőle.

Írjunk egy példaprogramot, amely egy nagyon nagy fájlt másol. Nem használhatjuk a readAllBytes()módszert a teljes fájl memóriába olvasására. Példa:

Kód jegyzet
String src = "c:\\projects\\log.txt";
String dest = "c:\\projects\\copy.txt";

try(FileInputStream input = new FileInputStream(src);
FileOutputStream output = new FileOutputStream(dest))
{
   byte[] buffer = new byte[65536]; // 64Kb
   while (input.available() > 0)
   {
      int real = input.read(buffer);
      output.write(buffer, 0, real);
   }
}



InputStreamfájlból való olvasáshoz fájlba
OutputStreamíráshoz

Puffer, amelybe beolvassuk az adatokat
Amíg van adat a folyamban

Adatok olvasása a pufferbe
Írja az adatokat a pufferből a második adatfolyamba

Ebben a példában két osztályt használtunk: FileInputStreama leszármazottja InputStreama fájlból való adatok olvasásához, és FileOutputStreama leszármazottja OutputStreamaz adatok fájlba írásához. A második óráról kicsit később beszélünk.

Egy másik érdekes pont itt a realváltozó. Amikor az utolsó adatblokkot beolvassák egy fájlból, könnyen előfordulhat, hogy 64 KB-nál kevesebb adat van benne. Ennek megfelelően nem a teljes puffert kell kiadnunk, hanem annak csak egy részét - az első realbájtokat. Pontosan ez történik a módszerben write().



3. Readerosztály

Az Readerosztály az osztály teljes analógja InputStream. Az egyetlen különbség az, hogy karakterekkel ( char) működik, bájtokkal nem. Csakúgy, mint az InputStreamosztály, az Readerosztály önmagában sehol nem használatos: több száz leszármazott osztály szülőosztálya, és mindegyikhez közös metódusokat határoz meg.

ReaderAz osztály (és az összes leszármazott osztály) módszerei :

Mód Leírás
int read()
Olvas egyet chara patakból
int read(char[] buffer)
Beolvas egy chartömböt az adatfolyamból
long skip(long n)
Kihagyja n charsaz adatfolyamot (elolvassa és eldobja őket)
boolean ready()
Ellenőrzi, hogy maradt-e még valami az adatfolyamban
void close()
Bezárja a patakot

A módszerek nagyon hasonlóak az osztály módszereihez InputStream, bár vannak apró eltérések.

int read()módszer

Ez a metódus beolvas egyet chara folyamból, és visszaadja. A chartípus kiszélesedik -re int, de az eredmény első két bájtja mindig nulla.

int read(char[] buffer)módszer

Ez a read()módszer második változata. Lehetővé teszi egy char tömb beolvasását egyből Reader. A karaktereket tároló tömböt argumentumként kell átadni. A metódus egy számot ad vissza – a ténylegesen beolvasott karakterek számát.

skip(long n)módszer

Ez a módszer lehetővé teszi az objektum első n karakterének kihagyását Reader. Pontosan ugyanúgy működik, mint az InputStreamosztály analóg metódusa. A ténylegesen kihagyott karakterek számát adja vissza.

boolean ready()módszer

Akkor tér vissza true, ha vannak olvasatlan bájtok az adatfolyamban.

void close()módszer

A close()metódus bezárja az adatfolyamot, és felszabadítja a hozzá tartozó külső erőforrásokat. Egy adatfolyam bezárása után nem lehet több adatot kiolvasni belőle.

Összehasonlításképpen írjunk egy programot, amely szöveges fájlt másol:

Kód jegyzet
String src = "c:\\projects\\log.txt";
String dest = "c:\\projects\\copy.txt";

try(FileReader reader = new FileReader(src);
FileWriter writer = new FileWriter(dest))
{
   char[] buffer = new char[65536]; // 128Kb
   while (reader.ready())
   {
      int real = reader.read(buffer);
      writer.write(buffer, 0, real);
   }
}



Readerfájlból való olvasáshoz fájlba
Writeríráshoz

Puffer, amelybe beolvassuk az adatokat
Amíg van adat a folyamban

Adatok olvasása pufferbe
Írja az adatokat a pufferből a második adatfolyamba