Ausblick: NIO
Die Probleme von java.io
- Streams, Reader, Writer und RandomAccessFile sind nicht kopierfrei
- Alle IO Operationen sind blockierend (blocking)
- Moderne Konzepte wie Memory-Mapped-Files werden nicht unterstützt
- Mit Java 1.4 wurde parallel zu java.io mit java.nio ein neues IO-Konzept eingeführt (nio = new IO, gesprochen „neio“) mit folgenden Eingenschaften
- kopierfrei
- nicht blockierend
- blockorientiert
- memory-mapped-files werden unerstützt
Java NIO (New I/O) ist ein Paket in der Java-Plattform, das in der Version 1.4 eingeführt wurde und eine Alternative zum herkömmlichen I/O-System darstellt. Das Paket wurde entwickelt, um die Leistung von Eingabe- und Ausgabevorgängen in Java-Anwendungen zu verbessern und flexiblere und skalierbare Netzwerk- und Dateiverarbeitungsfunktionen bereitzustellen.
Channels und Buffer
Die grundlegende Idee von Java NIO ist die Verwendung von sogenannten „non-blocking I/O“ Operationen, die eine asynchrone Verarbeitung ermöglichen. Im Gegensatz zum herkömmlichen I/O-System, können mit Java NIO mehrere I/O-Operationen parallel ausgeführt werden, ohne dass der Thread blockiert wird. Dies führt zu einer verbesserten Leistung und Skalierbarkeit von Java-Anwendungen.
Java NIO bietet auch eine flexiblere und leistungsstärkere Netzwerkverarbeitung durch die Verwendung von Channels und Buffers. Channels ermöglichen eine schnelle und direkte Verbindung zwischen der Anwendung und dem Netzwerk, während Buffers eine effiziente Möglichkeit bieten, Daten zu lesen und zu schreiben.
Ein weiterer Anwendungsbereich von Java NIO ist die Verarbeitung von Dateien. Mit dem Paket können Dateien schneller und effizienter gelesen und geschrieben werden, und es bietet auch erweiterte Funktionen wie Dateisperren, um eine gleichzeitige Bearbeitung von Dateien durch mehrere Threads oder Prozesse zu verhindern.
Die zentralen Elemente von NIO sind
Buffer
– Verwaltet gelesene und zu schreibende Daten. Es gibt Buffer für alle primitiven TypenByteBuffer
,CharBuffer
,ShortBuffer
,IntBuffer
,LongBuffer
,FloatBuffer
,DoubleBuffer
Channel
– Quelle bzw. Senke für Daten aus Buffers (ähnlich zu den Streams)- Können zum Lesen und Schreiben verwendet werden
- Werden nicht direkt erzeugt, sondern über die Klassen aus der Standard IO-Library
In Java NIO (New I/O) ist ein Channel
ein Objekt, das die Verbindung zwischen einer Quelle oder einem Ziel und der Anwendung darstellt. Es kann als eine Art Kanal oder Pipeline zwischen der Anwendung und der Quelle oder dem Ziel angesehen werden, über den Daten gelesen oder geschrieben werden können.
Die grundlegende Idee hinter Channels ist, dass sie eine schnelle und direkte Verbindung zwischen der Anwendung und der Quelle oder dem Ziel ermöglichen. Im Gegensatz zum herkömmlichen I/O-System, das eine langsame und schrittweise Verarbeitung von Daten durchführen kann, ermöglicht die Verwendung von Channels eine schnellere und effizientere Verarbeitung von Daten.
Channels bieten auch einige erweiterte Funktionen, wie beispielsweise Übertragungsoperationen, die eine schnelle Übertragung von Daten zwischen Kanälen ermöglichen. Dies kann insbesondere in Netzwerkverarbeitungsanwendungen nützlich sein, bei denen große Datenmengen schnell übertragen werden müssen.
Beispiel: Lesen in einen Buffer
FileInputStream fis = new FileInputStream("/tmp/test.txt");
FileChannel fc = fis.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
fc.read(buffer);
fis.close();
Beispiel: Schreiben aus einem Buffer
FileOutputStream fos = new FileOutputStream("/tmp/output.txt");
FileChannel fc = fos.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(128);
buffer.put("Hello World\n".getBytes());
buffer.flip();
fc.write(buffer);
fos.close();
>cat /tmp/output.txt
Hello World
Buffer
- Buffer werden über statische Factory-Methoden angelegt, z. B.
ByteBuffer buffer = ByteBuffer.allocate(1024);
- Jeder Buffer hat drei wichtige Eigenschaften
capacity
– Größe des Buffers, d. h. die Anzahl der Bytes etc. die er fassen kannposition
– Aktuelle Position des Lese- oder Schreibzeigers im Bufferlimit
– Grenze bis zu der der Buffer ausgelesen werden kann- Zusätzlich kann man, wie bei Streams, eine Marke (
mark
) setzen, so der Buffer dies unterstützt - Es gilt die Invariante
mark <= position <= limit <= capacity
DirectBuffer
greifen direkt auf Betriebssystemspeicher zu
Ein Buffer
ist ein Objekt, das verwendet wird, um Daten temporär zu speichern und die Übertragung von Daten zwischen Channels und Anwendungen zu erleichtern. Ein Buffer kann als eine Art Puffer oder Zwischenspeicher betrachtet werden, der zwischen dem Channel und der Anwendung platziert wird, um Daten zu lesen oder zu schreiben.
Ein Buffer wird erstellt, um eine bestimmte Menge an Daten aufzunehmen, und kann dann verwendet werden, um Daten aus dem Channel zu lesen oder in den Channel zu schreiben. Der Buffer speichert die Daten temporär, bevor sie in den Channel geschrieben oder aus dem Channel gelesen werden.
Beispiel: Kopierprogramm
// Quell und Zieldatei
String quelle = "/tmp/test.txt";
String ziel = "/tmp/ziel.txt";
// Streams und Channels für Quell und Zieldatei
FileInputStream in = new FileInputStream(quelle);
FileOutputStream out = new FileOutputStream(ziel);
FileChannel fcin = in.getChannel();
FileChannel fcout = out.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024); // Puffer für Dateiinhalt
// Daten aus Quell- in Zieldatei kopieren
while (fcin.read(buffer) >= 0) {
buffer.flip();
fcout.write(buffer);
buffer.clear();
}
// Streams schließen (channels werden automatisch geschlossen)
in.close();
out.close();
Methoden von Buffer
- Lesen
byte get()
ByteBuffer get(byte dst[])
ByteBuffer get(byte dst[], int offset, int length )
byte get(int index)
- Schreiben
ByteBuffer put(byte b)
ByteBuffer put(byte src[])
ByteBuffer put(byte src[], int offset, int length)
ByteBuffer put(ByteBuffer src)
ByteBuffer put(int index, byte b)
Weitere Features von NIO
- Memory mapped files
MappedByteBuffer mbb = fc.map(MapMode.READ_WRITE, 0, 1024);
- File Locks
FileLock lock = fc.lock(start, end, false);
- Asynchrone Socket I/O
- Automatisches Aufteilen oder Zusammenführen von Buffern
ScatheringByteChannel
GatheringByteChannel