Korábban megismerhettük az IO API-t (Input/Output Application Programming Interface) és a java.io csomagot, amelyek osztályai elsősorban a Java nyelvű streamekkel való munkára szolgálnak. A kulcs itt a patak fogalma .
Ma elkezdjük megvizsgálni a NIO API-t (új bemenet/kimenet).
A fő különbség az I/O két megközelítése között az, hogy az IO API adatfolyam-orientált, míg a NIO API pufferorientált. Tehát a legfontosabb megértendő fogalmak a pufferek és a csatornák .
Mi az a puffer és mi a csatorna?
A csatorna egy logikai portál, amelyen keresztül az adatok be- és kifelé mozognak, míg a puffer az átvitt adatok forrása vagy célállomása. A kimenet során a küldeni kívánt adatok egy pufferbe kerülnek, és a puffer továbbítja az adatokat a csatornának. A bevitel során a csatorna adatai a pufferbe kerülnek.
Más szavakkal:
- a puffer egyszerűen egy memóriablokk, amelybe információkat írhatunk, és amelyből információkat olvashatunk,
- a csatorna egy átjáró, amely hozzáférést biztosít az I/O eszközökhöz, például fájlokhoz vagy socketekhez.
A csatornák nagyon hasonlítanak a java.io csomagban található adatfolyamokhoz. Minden adatnak, amely bárhová eljut (vagy bárhonnan érkezik), át kell haladnia egy csatorna objektumon. Általában a NIO rendszer használatához kap egy csatornát egy I/O entitáshoz és egy puffert az adatok tárolására. Ezután a pufferrel dolgozik, szükség szerint be- vagy kiadva adatokat.
A pufferben előre-hátra mozoghat, azaz "sétálhat" a pufferben, amit streamekben nem tudna megtenni. Ez nagyobb rugalmasságot biztosít az adatok feldolgozásakor. A szabványos könyvtárban a puffereket az absztrakt Buffer osztály és annak több leszármazottja képviseli :
- ByteBuffer
- CharBuffer
- ShortBuffer
- IntBuffer
- FloatBuffer
- DoubleBuffer
- LongBuffer
A fő különbség az alosztályok között az általuk tárolt adattípus – bájtok , int , long és egyéb primitív adattípusok.
Puffer tulajdonságai
A puffernek négy fő tulajdonsága van. Ezek a kapacitás, határérték, pozíció és jel.
A kapacitás a pufferben tárolható adat/bájt maximális mennyisége. A puffer kapacitása nem módosítható . Ha egy puffer megtelt, törölni kell, mielőtt többet írna bele.
Írási módban a puffer korlátja megegyezik a kapacitásával, ami a pufferbe írható maximális adatmennyiséget jelzi. Olvasási módban a puffer korlátja a pufferből kiolvasható adatok maximális mennyiségére vonatkozik.
A pozíció a kurzor aktuális pozícióját jelzi a pufferben. A puffer létrehozásakor kezdetben 0-ra van állítva. Más szóval, ez a következő olvasandó vagy írandó elem indexe.
A jel a kurzor pozíciójának mentésére szolgál. Miközben egy puffert manipulálunk, a kurzor pozíciója folyamatosan változik, de mindig vissza tudjuk állítani az előzőleg megjelölt pozícióba.
A pufferrel való munkavégzés módszerei
Most nézzük meg a fő metóduskészletet, amely lehetővé teszi, hogy a pufferünkkel (memóriablokkunkkal) dolgozzunk az adatok olvasásához és csatornákba való írásához.
-
allokáció(int kapacitás) – ez a módszer egy új puffer lefoglalására szolgál a megadott kapacitással. Az allocate() metódus IllegalArgumentException kivételt dob , ha az átadott kapacitás negatív egész szám.
-
kapacitás() az aktuális puffer kapacitását adja vissza .
-
position() a kurzor aktuális pozícióját adja vissza. Az olvasási és írási műveletek a kurzort a puffer végére mozgatják. A visszatérési érték mindig kisebb vagy egyenlő a határértékkel.
-
limit() az aktuális puffer korlátját adja vissza.
-
mark() a kurzor aktuális pozíciójának megjelölésére (mentésére) szolgál.
-
A reset() visszaállítja a kurzort az előzőleg megjelölt (mentett) pozícióba.
-
clear() nullára állítja a pozíciót, és beállítja a kapacitás korlátját. Ez a módszer nem törli a pufferben lévő adatokat. Csak a pozíciót, a határértéket és a jelölést inicializálja újra.
-
A flip() a puffert írási módból olvasási módba kapcsolja. Ezenkívül beállítja a határértéket az aktuális pozícióra, majd visszaállítja a pozíciót nullára.
-
read() – A csatorna olvasási metódusa a csatornából a pufferbe írandó adatok, míg a puffer put() metódusa az adatok pufferbe írására szolgál.
-
write() – A csatorna írási metódusa az adatok pufferből a csatornába írásához, míg a puffer get() metódusa a pufferből való adatok olvasásához.
-
rewind() visszatekeri a puffert. Ezt a módszert akkor használják, ha újra kell olvasnia a puffert – nullára állítja a pozíciót, és nem módosítja a határértéket.
És most néhány szó a csatornákról.
A Java NIO legfontosabb csatornamegvalósításai a következő osztályok:
-
FileChannel — Egy csatorna adatok fájlból/fájlba való olvasásához és írásához.
-
DatagramChannel – Ez az osztály adatokat olvas és ír a hálózaton keresztül UDP-n (User Datagram Protocol) keresztül.
-
SocketChannel — Adatok olvasására és írására szolgáló csatorna a hálózaton keresztül TCP-n (Transmission Control Protocol) keresztül.
-
ServerSocketChannel – TCP-kapcsolaton keresztüli adatok olvasására és írására szolgáló csatorna, akárcsak egy webszerver. Minden bejövő kapcsolathoz létrejönegy SocketChannel .
Gyakorlat
Ideje írni néhány sor kódot. Először olvassuk el a fájlt, és jelenítsük meg a tartalmát a konzolon, majd írjunk valamilyen karakterláncot a fájlba.
A kód sok megjegyzést tartalmaz – remélem, segítenek megérteni, hogyan működik minden:
// Create a RandomAccessFile object, passing in the file path
// and a string that says the file will be opened for reading and writing
try (RandomAccessFile randomAccessFile = new RandomAccessFile("text.txt", "rw");
// Get an instance of the FileChannel class
FileChannel channel = randomAccessFile.getChannel();
) {
// Our file is small, so we'll read it in one go
// Create a buffer of the required size based on the size of our channel
ByteBuffer byteBuffer = ByteBuffer.allocate((int) channel.size());
// Read data will be put into a StringBuilder
StringBuilder builder = new StringBuilder();
// Write data from the channel to the buffer
channel.read(byteBuffer);
// Switch the buffer from write mode to read mode
byteBuffer.flip();
// In a loop, write data from the buffer to the StringBuilder
while (byteBuffer.hasRemaining()) {
builder.append((char) byteBuffer.get());
}
// Display the contents of the StringBuilder on the console
System.out.println(builder);
// Now let's continue our program and write data from a string to the file
// Create a string with arbitrary text
String someText = "Hello, Amigo!!!!!";
// Create a new buffer for writing,
// but let the channel remain the same, because we're going to the same file
// In other words, we can use one channel for both reading and writing to a file
// Create a buffer specifically for our string — convert the string into an array and get its length
ByteBuffer byteBuffer2 = ByteBuffer.allocate(someText.getBytes().length);
// Write our string to the buffer
byteBuffer2.put(someText.getBytes());
// Switch the buffer from write mode to read mode
// so that the channel can read from the buffer and write our string to the file
byteBuffer2.flip();
// The channel reads the information from the buffer and writes it to our file
channel.write(byteBuffer2);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Próbálja ki a NIO API -t – imádni fogja!
GO TO FULL VERSION