Java NIO - Kurzanleitung
Das Java.nio-Paket wurde in Java 1.4 eingeführt. Im Gegensatz zu Java I / O in Java NIO wird der puffer- und kanalorientierte Datenfluss für E / A-Operationen eingeführt, der eine schnellere Ausführung und eine bessere Leistung bietet.
Außerdem bietet die NIO-API Selektoren, mit denen die Funktionalität des Abhörens mehrerer Kanäle für E / A-Ereignisse auf asynchrone oder nicht blockierende Weise eingeführt wird. In NIO sind die zeitaufwändigsten E / A-Aktivitäten einschließlich des Füllens und Entleerens von Puffern für das Betriebssystem mit zunehmender Geschwindigkeit.
Die zentralen Abstraktionen der NIO-APIs lauten wie folgt:
Puffer, die Container für Daten, Zeichensätze und die zugehörigen Decoder und Encoder sind, die zwischen Bytes und Unicode-Zeichen übersetzt werden.
Kanäle verschiedener Typen, die Verbindungen zu Entitäten darstellen, die E / A-Operationen ausführen können
Selektoren und Auswahltasten, die zusammen mit auswählbaren Kanälen eine gemultiplexte, nicht blockierende E / A-Funktion definieren.
In diesem Abschnitt erfahren Sie, wie Sie Java auf Ihren Computer herunterladen und einrichten. Führen Sie die folgenden Schritte aus, um die Umgebung einzurichten.
Java SE ist frei verfügbar über den Link Java herunterladen . Sie laden also eine Version herunter, die auf Ihrem Betriebssystem basiert.
Befolgen Sie die Anweisungen, um Java herunterzuladen und auszuführen .exeum Java auf Ihrem Computer zu installieren. Sobald Sie Java auf Ihrem Computer installiert haben, müssen Sie Umgebungsvariablen festlegen, die auf korrekte Installationsverzeichnisse verweisen.
Einrichten des Pfads für Windows 2000 / XP
Angenommen, Sie haben Java im Verzeichnis c: \ Programme \ java \ jdk installiert -
Klicken Sie mit der rechten Maustaste auf "Arbeitsplatz" und wählen Sie "Eigenschaften".
Klicken Sie auf der Registerkarte "Erweitert" auf die Schaltfläche "Umgebungsvariablen".
Ändern Sie nun die Variable 'Path' so, dass sie auch den Pfad zur ausführbaren Java-Datei enthält. Wenn der Pfad derzeit auf "C: \ WINDOWS \ SYSTEM32" festgelegt ist, ändern Sie Ihren Pfad in "C: \ WINDOWS \ SYSTEM32; c: \ Programme \ java \ jdk \ bin".
Einrichten des Pfads für Windows 95/98 / ME
Angenommen, Sie haben Java im Verzeichnis c: \ Programme \ java \ jdk installiert -
Bearbeiten Sie die Datei 'C: \ autoexec.bat' und fügen Sie am Ende die folgende Zeile hinzu:
'SET PATH =% PATH%; C: \ Programme \ java \ jdk \ bin'
Einrichten des Pfads für Linux, UNIX, Solaris, FreeBSD
Die Umgebungsvariable PATH sollte so eingestellt werden, dass sie darauf verweist, wo die Java-Binärdateien installiert wurden. Informationen hierzu finden Sie in Ihrer Shell-Dokumentation.
Wenn Sie beispielsweise bash als Shell verwenden, fügen Sie die folgende Zeile am Ende Ihrer '.bashrc: export PATH = / path / to / java: $ PATH' hinzu.
Beliebte Java-Editoren
Zum Schreiben Ihrer Java-Programme benötigen Sie einen Texteditor. Es gibt noch ausgefeiltere IDE auf dem Markt. Im Moment können Sie jedoch eine der folgenden Möglichkeiten in Betracht ziehen:
Notepad - Auf einem Windows-Computer können Sie einen einfachen Texteditor wie Notepad (für dieses Lernprogramm empfohlen) und TextPad verwenden.
Netbeans - ist eine Java-IDE, die Open Source und kostenlos ist und von der heruntergeladen werden kann http://www.netbeans.org/index.html.
Eclipse - ist auch eine Java-IDE, die von der Open-Source-Community von Eclipse entwickelt wurde und von heruntergeladen werden kann https://www.eclipse.org/.
Wie wir wissen, wird Java NIO zur Weiterentwicklung der herkömmlichen Java-E / A-API eingeführt. Die wichtigsten Verbesserungen, die NIO effizienter als E / A machen, sind das in NIO verwendete Kanaldatenflussmodell und die Verwendung des Betriebssystems für herkömmliche E / A-Aufgaben.
Der Unterschied zwischen Java NIO und Java IO kann wie folgt erklärt werden:
Wie im vorherigen Beitrag in NIO-Puffer und kanalorientierter Datenfluss für E / A-Vorgänge erwähnt, die im Vergleich zu IO eine schnellere Ausführung und eine bessere Leistung bieten. NIO verwendet auch das Betriebssystem für herkömmliche E / A-Aufgaben, was es wiederum effizienter macht.
Ein weiterer Aspekt des Unterschieds zwischen NIO und E / A besteht darin, dass dieses E / A den Datenstrom der Stromleitung verwendet, dh jeweils ein Byte, und Datenobjekte in Bytes konvertiert und umgekehrt, während NIO sich mit den Datenblöcken befasst, bei denen es sich um Byteblöcke handelt.
In Java sind E / A-Stream-Objekte unidirektional, während in NIO-Kanälen bidirektional sind, was bedeutet, dass ein Kanal sowohl zum Lesen als auch zum Schreiben von Daten verwendet werden kann.
Der Streamline-Datenfluss in IO erlaubt kein Hin- und Herbewegen in den Daten. Wenn Sie sich in den aus einem Stream gelesenen Daten hin und her bewegen müssen, müssen Sie sie zuerst in einem Puffer zwischenspeichern. Im Fall von NIO verwenden wir pufferorientiert Dies ermöglicht den Hin- und Herzugriff auf Daten, ohne dass ein Caching erforderlich ist.
Die NIO-API unterstützt auch Multithreading, sodass Daten asynchron gelesen und geschrieben werden können, sodass der aktuelle Thread während der Ausführung von E / A-Vorgängen nicht blockiert wird. Dies macht ihn wiederum effizienter als die herkömmliche Java-E / A-API.
Das Konzept des Multithreading wird mit der Einführung von eingeführt Selectors in Java NIO, mit dem mehrere Kanäle auf asynchrone oder nicht blockierende Weise auf E / A-Ereignisse abgehört werden können.
Multithreading in NIO macht es nicht blockierend, was bedeutet, dass der Thread nur dann zum Lesen oder Schreiben aufgefordert wird, wenn Daten verfügbar sind, andernfalls kann der Thread in der Zwischenzeit für andere Aufgaben verwendet werden. Dies ist jedoch bei herkömmlichem Java-E / A nicht möglich, da kein Multithreading erfolgt wird darin unterstützt, was es als Blockierung macht.
Mit NIO können mehrere Kanäle mit nur einem Thread verwaltet werden. Die Kosten für das Parsen der Daten sind jedoch möglicherweise etwas komplizierter als beim Lesen von Daten aus einem blockierenden Stream bei Java IO.So für den Fall, dass weniger Verbindungen mit sehr hoher Bandbreite erforderlich sind Wenn Sie viele Daten gleichzeitig senden, ist die Java-E / A-API in diesem Fall möglicherweise die beste Lösung.
Beschreibung
Wie der Name schon sagt, wird der Kanal als Mittelwert des Datenflusses von einem Ende zum anderen verwendet. Hier in Java verhält sich der NIO-Kanal zwischen dem Puffer und einer Entität am anderen Ende gleich, mit anderen Worten, der Kanal wird zum Lesen von Daten zum Puffern und auch zum Schreiben von Daten aus dem Puffer verwendet.
Im Gegensatz zu Streams, die in herkömmlichen Java-E / A-Kanälen verwendet werden, gibt es zwei Möglichkeiten, dh Lesen und Schreiben. Der Java-NIO-Kanal unterstützt den asynchronen Datenfluss sowohl im blockierenden als auch im nicht blockierenden Modus.
Implementierungen von Channel
Der Java NIO-Kanal wird hauptsächlich in folgenden Klassen implementiert:
FileChannel- Um Daten aus einer Datei zu lesen, verwenden wir den Dateikanal. Das Objekt des Dateikanals kann nur durch Aufrufen der Methode getChannel () für das Dateiobjekt erstellt werden, da das Dateiobjekt nicht direkt erstellt werden kann.
DatagramChannel - Der Datagrammkanal kann die Daten über das Netzwerk über UDP (User Datagram Protocol) lesen und schreiben. Das Objekt von DataGramchannel kann mit Factory-Methoden erstellt werden.
SocketChannel- Der SocketChannel-Kanal kann die Daten über TCP (Transmission Control Protocol) über das Netzwerk lesen und schreiben. Es werden auch die Factory-Methoden zum Erstellen des neuen Objekts verwendet.
ServerSocketChannel- Der ServerSocketChannel liest und schreibt die Daten über TCP-Verbindungen, genau wie ein Webserver. Für jede eingehende Verbindung wird ein SocketChannel erstellt.
Beispiel
Das folgende Beispiel liest aus einer Textdatei aus C:/Test/temp.txt und druckt den Inhalt auf die Konsole.
temp.txt
Hello World!
ChannelDemo.java
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class ChannelDemo {
public static void main(String args[]) throws IOException {
RandomAccessFile file = new RandomAccessFile("C:/Test/temp.txt", "r");
FileChannel fileChannel = file.getChannel();
ByteBuffer byteBuffer = ByteBuffer.allocate(512);
while (fileChannel.read(byteBuffer) > 0) {
// flip the buffer to prepare for get operation
byteBuffer.flip();
while (byteBuffer.hasRemaining()) {
System.out.print((char) byteBuffer.get());
}
}
file.close();
}
}
Ausgabe
Hello World!
Beschreibung
Wie bereits erwähnt, wird die FileChannel-Implementierung des Java NIO-Kanals eingeführt, um auf Metadateneigenschaften der Datei zuzugreifen, einschließlich Erstellung, Änderung, Größe usw. Außerdem sind die Dateikanäle mit mehreren Threads versehen, was Java NIO wiederum effizienter macht als Java IO.
Im Allgemeinen können wir sagen, dass FileChannel ein Kanal ist, der mit einer Datei verbunden ist, über die Sie Daten aus einer Datei lesen und in eine Datei schreiben können. Ein weiteres wichtiges Merkmal von FileChannel ist, dass es nicht in den nicht blockierenden Modus versetzt werden kann und läuft immer im Blockiermodus.
Wir können das Dateikanalobjekt nicht direkt abrufen. Das Objekt des Dateikanals wird entweder von - erhalten
getChannel() - Methode für FileInputStream, FileOutputStream oder RandomAccessFile.
open() - Methode des Dateikanals, die den Kanal standardmäßig öffnet.
Der Objekttyp des Dateikanals hängt vom Typ der Klasse ab, die bei der Objekterstellung aufgerufen wird. Wenn also ein Objekt durch Aufrufen der getchannel-Methode von FileInputStream erstellt wird, wird der Dateikanal zum Lesen geöffnet und löst NonWritableChannelException aus, falls versucht wird, darauf zu schreiben.
Beispiel
Das folgende Beispiel zeigt das Lesen und Schreiben von Daten aus Java NIO FileChannel.
Das folgende Beispiel liest aus einer Textdatei aus C:/Test/temp.txt und druckt den Inhalt auf die Konsole.
temp.txt
Hello World!
FileChannelDemo.java
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.HashSet;
import java.util.Set;
public class FileChannelDemo {
public static void main(String args[]) throws IOException {
//append the content to existing file
writeFileChannel(ByteBuffer.wrap("Welcome to TutorialsPoint".getBytes()));
//read the file
readFileChannel();
}
public static void readFileChannel() throws IOException {
RandomAccessFile randomAccessFile = new RandomAccessFile("C:/Test/temp.txt",
"rw");
FileChannel fileChannel = randomAccessFile.getChannel();
ByteBuffer byteBuffer = ByteBuffer.allocate(512);
Charset charset = Charset.forName("US-ASCII");
while (fileChannel.read(byteBuffer) > 0) {
byteBuffer.rewind();
System.out.print(charset.decode(byteBuffer));
byteBuffer.flip();
}
fileChannel.close();
randomAccessFile.close();
}
public static void writeFileChannel(ByteBuffer byteBuffer)throws IOException {
Set<StandardOpenOption> options = new HashSet<>();
options.add(StandardOpenOption.CREATE);
options.add(StandardOpenOption.APPEND);
Path path = Paths.get("C:/Test/temp.txt");
FileChannel fileChannel = FileChannel.open(path, options);
fileChannel.write(byteBuffer);
fileChannel.close();
}
}
Ausgabe
Hello World! Welcome to TutorialsPoint
Java NIO Datagram wird als Kanal verwendet, der UDP-Pakete über ein Protokoll ohne Verbindung senden und empfangen kann. Der Standard-Datagrammkanal blockiert, während er im nicht blockierenden Modus verwendet werden kann. Um ihn nicht zu blockieren, können wir configureBlocking ( false) method.DataGram-Kanal kann geöffnet werden, indem eine der statischen Methoden mit dem Namen as aufgerufen wird open() Die IP-Adresse kann auch als Parameter verwendet werden, damit sie für Multi-Casting verwendet werden kann.
Der Datagrammkanal von FileChannel ist standardmäßig nicht verbunden, um eine Verbindung herzustellen. Wir müssen seine connect () -Methode explizit aufrufen. Der Datagrammkanal muss jedoch nicht verbunden sein, damit die Sende- und Empfangsmethoden verwendet werden können, während er verbunden sein muss um die Lese- und Schreibmethoden zu verwenden, da diese Methoden keine Socket-Adressen akzeptieren oder zurückgeben.
Wir können den Verbindungsstatus des Datagrammkanals überprüfen, indem wir dessen aufrufen isConnected() Sobald eine Verbindung hergestellt ist, bleibt ein Datagrammkanal verbunden, bis er getrennt oder geschlossen wird. Datagrammkanäle sind threadsicher und unterstützen gleichzeitig Multithreading und Parallelität.
Wichtige Methoden des Datagrammkanals
bind(SocketAddress local) - Diese Methode wird verwendet, um den Socket des Datagrammkanals an die lokale Adresse zu binden, die als Parameter für diese Methode angegeben wird.
connect(SocketAddress remote) - Mit dieser Methode wird der Socket mit der Remote-Adresse verbunden.
disconnect() - Mit dieser Methode wird der Socket von der Remote-Adresse getrennt.
getRemoteAddress() - Diese Methode gibt die Adresse des Remote-Standorts zurück, an den der Socket des Kanals angeschlossen ist.
isConnected() - Wie bereits erwähnt, gibt diese Methode den Verbindungsstatus des Datagrammkanals zurück, dh ob er verbunden ist oder nicht.
open() and open(ProtocolFamily family) - Die offene Methode wird verwendet, um einen Datagrammkanal für eine einzelne Adresse zu öffnen, während die offene Methode der parametrisierten offenen Methode für mehrere Adressen verwendet wird, die als Protokollfamilie dargestellt werden.
read(ByteBuffer dst) - Diese Methode wird verwendet, um Daten aus dem angegebenen Puffer über den Datagrammkanal zu lesen.
receive(ByteBuffer dst) - Mit dieser Methode wird ein Datagramm über diesen Kanal empfangen.
send(ByteBuffer src, SocketAddress target) - Mit dieser Methode wird ein Datagramm über diesen Kanal gesendet.
Beispiel
Das folgende Beispiel zeigt, wie Daten von Java NIO DataGramChannel gesendet werden.
Server: DatagramChannelServer.java
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
public class DatagramChannelServer {
public static void main(String[] args) throws IOException {
DatagramChannel server = DatagramChannel.open();
InetSocketAddress iAdd = new InetSocketAddress("localhost", 8989);
server.bind(iAdd);
System.out.println("Server Started: " + iAdd);
ByteBuffer buffer = ByteBuffer.allocate(1024);
//receive buffer from client.
SocketAddress remoteAdd = server.receive(buffer);
//change mode of buffer
buffer.flip();
int limits = buffer.limit();
byte bytes[] = new byte[limits];
buffer.get(bytes, 0, limits);
String msg = new String(bytes);
System.out.println("Client at " + remoteAdd + " sent: " + msg);
server.send(buffer,remoteAdd);
server.close();
}
}
Ausgabe
Server Started: localhost/127.0.0.1:8989
Client: DatagramChannelClient.java
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
public class DatagramChannelClient {
public static void main(String[] args) throws IOException {
DatagramChannel client = null;
client = DatagramChannel.open();
client.bind(null);
String msg = "Hello World!";
ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
InetSocketAddress serverAddress = new InetSocketAddress("localhost",
8989);
client.send(buffer, serverAddress);
buffer.clear();
client.receive(buffer);
buffer.flip();
client.close();
}
}
Ausgabe
Wenn Sie den Client ausführen, wird die folgende Ausgabe auf dem Server gedruckt.
Server Started: localhost/127.0.0.1:8989
Client at /127.0.0.1:64857 sent: Hello World!
Der Java NIO-Socket-Kanal ist ein Kanal vom Typ "Auswählbar". Dies bedeutet, dass er mithilfe eines Selektors gemultiplext werden kann, der für Stream-orientierte Datenfluss-Verbindungssockets verwendet wird. Der Socket-Kanal kann durch Aufrufen seiner statischen Daten erstellt werden open() Methode, vorausgesetzt, ein bereits vorhandener Socket ist noch nicht vorhanden. Der Socket-Kanal wird durch Aufrufen der offenen Methode erstellt, ist jedoch noch nicht verbunden. Um den Socket-Kanal zu verbinden connect() Eine Methode, die hier erwähnt werden soll, ist, wenn der Kanal nicht verbunden ist und versucht wird, eine E / A-Operation auszuführen, dann wird von diesem Kanal eine NotYetConnectedException ausgelöst. Daher muss sichergestellt werden, dass der Kanal verbunden ist, bevor eine E / A ausgeführt wird Sobald der Kanal verbunden ist, bleibt er verbunden, bis er geschlossen wird. Der Status des Socket-Kanals kann durch Aufrufen seines Kanals bestimmt werden isConnected Methode.
Die Verbindung des Socket-Kanals kann durch Aufrufen von finishConnect() Ob ein Verbindungsvorgang ausgeführt wird oder nicht, kann durch Aufrufen der Methode isConnectionPending ermittelt werden. Der Standard-Socket-Kanal unterstützt eine nicht blockierende Verbindung. Außerdem wird das asynchrone Herunterfahren unterstützt, ähnlich dem in der Channel-Klasse angegebenen asynchronen Schließvorgang.
Socket-Kanäle können sicher von mehreren gleichzeitigen Threads verwendet werden. Sie unterstützen das gleichzeitige Lesen und Schreiben, obwohl höchstens ein Thread lesen und höchstens ein Thread zu einem bestimmten Zeitpunkt schreiben kann. Die Methoden connect und finishConnect werden miteinander synchronisiert, und ein Versuch, eine Lese- oder Schreiboperation zu initiieren, während ein Aufruf einer dieser Methoden ausgeführt wird, wird blockiert, bis dieser Aufruf abgeschlossen ist.
Wichtige Methoden des Socket-Kanals
bind(SocketAddress local) - Mit dieser Methode wird der Socket-Kanal an die lokale Adresse gebunden, die als Parameter für diese Methode angegeben wird.
connect(SocketAddress remote) - Mit dieser Methode wird der Socket mit der Remote-Adresse verbunden.
finishConnect() - Mit dieser Methode wird der Vorgang zum Anschließen eines Socket-Kanals abgeschlossen.
getRemoteAddress() - Diese Methode gibt die Adresse des Remote-Standorts zurück, an den der Socket des Kanals angeschlossen ist.
isConnected() - Wie bereits erwähnt, gibt diese Methode den Verbindungsstatus des Socket-Kanals zurück, dh ob dieser angeschlossen ist oder nicht.
open() and open((SocketAddress remote) - Die Open-Methode wird verwendet, um einen Socket-Kanal für keine angegebene Adresse zu öffnen, während die Open-Methode für die angegebene Remote-Adresse parametrisiert wird. Außerdem wird eine Verbindung hergestellt. Diese Convenience-Methode funktioniert so, als würde die open () -Methode aufgerufen und die connect-Methode beim Ergebnis aufgerufen Socket-Kanal, weiterleiten und dann diesen Kanal zurückgeben.
read(ByteBuffer dst) - Diese Methode wird verwendet, um Daten aus dem angegebenen Puffer über den Socket-Kanal zu lesen.
isConnectionPending() - Diese Methode gibt an, ob auf diesem Kanal ein Verbindungsvorgang ausgeführt wird.
Beispiel
Das folgende Beispiel zeigt, wie Daten von Java NIO SocketChannel gesendet werden.
C: /Test/temp.txt
Hello World!
Client: SocketChannelClient.java
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.EnumSet;
public class SocketChannelClient {
public static void main(String[] args) throws IOException {
ServerSocketChannel serverSocket = null;
SocketChannel client = null;
serverSocket = ServerSocketChannel.open();
serverSocket.socket().bind(new InetSocketAddress(9000));
client = serverSocket.accept();
System.out.println("Connection Set: " + client.getRemoteAddress());
Path path = Paths.get("C:/Test/temp1.txt");
FileChannel fileChannel = FileChannel.open(path,
EnumSet.of(StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING,
StandardOpenOption.WRITE)
);
ByteBuffer buffer = ByteBuffer.allocate(1024);
while(client.read(buffer) > 0) {
buffer.flip();
fileChannel.write(buffer);
buffer.clear();
}
fileChannel.close();
System.out.println("File Received");
client.close();
}
}
Ausgabe
Wenn Sie den Client ausführen, wird nichts gedruckt, bis der Server gestartet wird.
Server: SocketChannelServer.java
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
public class SocketChannelServer {
public static void main(String[] args) throws IOException {
SocketChannel server = SocketChannel.open();
SocketAddress socketAddr = new InetSocketAddress("localhost", 9000);
server.connect(socketAddr);
Path path = Paths.get("C:/Test/temp.txt");
FileChannel fileChannel = FileChannel.open(path);
ByteBuffer buffer = ByteBuffer.allocate(1024);
while(fileChannel.read(buffer) > 0) {
buffer.flip();
server.write(buffer);
buffer.clear();
}
fileChannel.close();
System.out.println("File Sent");
server.close();
}
}
Ausgabe
Wenn Sie den Server ausführen, wird Folgendes gedruckt.
Connection Set: /127.0.0.1:49558
File Received
Der Java NIO-Server-Socket-Kanal ist wieder ein auswählbarer Typkanal, der für den Stream-orientierten Datenfluss verwendet wird, der Sockets verbindet. Der Server-Socket-Kanal kann durch Aufrufen seines statischen Kanals erstellt werden open() Methode, vorausgesetzt, ein bereits vorhandener Socket ist noch nicht vorhanden. Server Socket-Kanal wird durch Aufrufen der offenen Methode erstellt, aber noch nicht gebunden. Um den Socket-Kanal zu binden bind() Methode ist aufzurufen.
Ein Punkt, der hier erwähnt werden muss, ist, wenn der Kanal nicht gebunden ist und versucht wird, eine E / A-Operation auszuführen, wird von diesem Kanal eine NotYetBoundException ausgelöst. Daher muss sichergestellt werden, dass der Kanal begrenzt ist, bevor eine E / A-Operation ausgeführt wird.
Eingehende Verbindungen für den Server-Socket-Kanal werden durch Aufrufen der ServerSocketChannel.accept () -Methode abgehört. Wenn die accept () -Methode zurückgegeben wird, gibt sie einen SocketChannel mit einer eingehenden Verbindung zurück. Daher blockiert die Methode accept (), bis eine eingehende Verbindung eintrifft. Wenn sich der Kanal im nicht blockierenden Modus befindet, gibt die Methode accept sofort null zurück, wenn keine ausstehenden Verbindungen vorhanden sind. Andernfalls wird es auf unbestimmte Zeit blockiert, bis eine neue Verbindung verfügbar ist oder ein E / A-Fehler auftritt.
Der Sockel des neuen Kanals ist zunächst ungebunden. Es muss über eine der Bindemethoden seines Sockets an eine bestimmte Adresse gebunden werden, bevor Verbindungen akzeptiert werden können. Außerdem wird der neue Kanal durch Aufrufen der openServerSocketChannel-Methode des systemweiten Standardobjekts SelectorProvider erstellt.
Wie Socket Channel Server Socket Channel könnte Daten mit lesen read()Methode. Zunächst wird der Puffer zugewiesen. Die von einem ServerSocketChannel gelesenen Daten werden im Puffer gespeichert. Zweitens rufen wir die ServerSocketChannel.read () -Methode auf und lesen die Daten von einem ServerSocketChannel in einen Puffer. Der ganzzahlige Wert der read () -Methode gibt zurück, wie viele Bytes in den Puffer geschrieben wurden
In ähnlicher Weise könnten Daten mit in den Server-Socket-Kanal geschrieben werden write() Methode, die Buffer als Parameter verwendet. Verwendet üblicherweise die Write-Methode in einer while-Schleife, um die write () -Methode zu wiederholen, bis für den Buffer keine weiteren Bytes zum Schreiben verfügbar sind.
Wichtige Methoden des Socket-Kanals
bind(SocketAddress local) - Mit dieser Methode wird der Socket-Kanal an die lokale Adresse gebunden, die als Parameter für diese Methode angegeben wird.
accept() - Mit dieser Methode wird eine Verbindung zum Socket dieses Kanals akzeptiert.
connect(SocketAddress remote) - Mit dieser Methode wird der Socket mit der Remote-Adresse verbunden.
finishConnect() - Mit dieser Methode wird der Vorgang zum Anschließen eines Socket-Kanals abgeschlossen.
getRemoteAddress() - Diese Methode gibt die Adresse des Remote-Standorts zurück, an den der Socket des Kanals angeschlossen ist.
isConnected() - Wie bereits erwähnt, gibt diese Methode den Verbindungsstatus des Socket-Kanals zurück, dh ob dieser angeschlossen ist oder nicht.
open() - Die Open-Methode wird verwendet, um einen Socket-Kanal für keine angegebene Adresse zu öffnen. Diese Convenience-Methode funktioniert so, als würde die open () -Methode aufgerufen, die Connect-Methode für den resultierenden Server-Socket-Kanal aufgerufen, ihn remote übergeben und dieser Kanal dann zurückgegeben.
read(ByteBuffer dst) - Diese Methode wird verwendet, um Daten aus dem angegebenen Puffer über den Socket-Kanal zu lesen.
setOption(SocketOption<T> name, T value) - Diese Methode legt den Wert einer Socket-Option fest.
socket() - Diese Methode ruft einen diesem Kanal zugeordneten Server-Socket ab.
validOps() - Diese Methode gibt einen Operationssatz zurück, der die unterstützten Operationen dieses Kanals identifiziert. Server-Socket-Kanäle unterstützen nur das Akzeptieren neuer Verbindungen, daher gibt diese Methode SelectionKey.OP_ACCEPT zurück.
Beispiel
Das folgende Beispiel zeigt, wie Daten von Java NIO ServerSocketChannel gesendet werden.
C: /Test/temp.txt
Hello World!
Client: SocketChannelClient.java
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.EnumSet;
public class SocketChannelClient {
public static void main(String[] args) throws IOException {
ServerSocketChannel serverSocket = null;
SocketChannel client = null;
serverSocket = ServerSocketChannel.open();
serverSocket.socket().bind(new InetSocketAddress(9000));
client = serverSocket.accept();
System.out.println("Connection Set: " + client.getRemoteAddress());
Path path = Paths.get("C:/Test/temp1.txt");
FileChannel fileChannel = FileChannel.open(path,
EnumSet.of(StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING,
StandardOpenOption.WRITE)
);
ByteBuffer buffer = ByteBuffer.allocate(1024);
while(client.read(buffer) > 0) {
buffer.flip();
fileChannel.write(buffer);
buffer.clear();
}
fileChannel.close();
System.out.println("File Received");
client.close();
}
}
Ausgabe
Wenn Sie den Client ausführen, wird nichts gedruckt, bis der Server gestartet wird.
Server: SocketChannelServer.java
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
public class SocketChannelServer {
public static void main(String[] args) throws IOException {
SocketChannel server = SocketChannel.open();
SocketAddress socketAddr = new InetSocketAddress("localhost", 9000);
server.connect(socketAddr);
Path path = Paths.get("C:/Test/temp.txt");
FileChannel fileChannel = FileChannel.open(path);
ByteBuffer buffer = ByteBuffer.allocate(1024);
while(fileChannel.read(buffer) > 0) {
buffer.flip();
server.write(buffer);
buffer.clear();
}
fileChannel.close();
System.out.println("File Sent");
server.close();
}
}
Ausgabe
Wenn Sie den Server ausführen, wird Folgendes gedruckt.
Connection Set: /127.0.0.1:49558
File Received
Da wir wissen, dass Java NIO im Vergleich zur herkömmlichen E / A-API von Java eine optimierte API für Daten-E / A-Operationen ist. Eine weitere zusätzliche Unterstützung, die Java NIO bietet, ist das Lesen / Schreiben von Daten von / zu mehreren Puffern in den Kanal Die Schreibunterstützung wird als Scatter and Gather bezeichnet, bei der Daten bei Lesedaten von einem Kanal auf mehrere Puffer gestreut werden, während bei Schreibdaten Daten von mehreren Puffern auf einen einzelnen Kanal gesammelt werden.
Um dieses mehrfache Lesen und Schreiben vom Kanal zu erreichen, gibt es die ScatteringByteChannel- und GatheringByteChannel-API, die Java NIO zum Lesen und Schreiben der Daten bereitstellt, wie im folgenden Beispiel dargestellt.
ScatteringByteChannel
Read from multiple channels - In diesem Fall haben wir Daten von einem einzelnen Kanal in mehrere Puffer gelesen. Dazu werden mehrere Puffer zugewiesen und einem Array vom Puffertyp hinzugefügt. Dann wird dieses Array als Parameter an die Methode ScatteringByteChannel read () übergeben, aus der dann Daten geschrieben werden Der Kanal in der Reihenfolge, in der die Puffer im Array auftreten. Sobald ein Puffer voll ist, fährt der Kanal fort, um den nächsten Puffer zu füllen.
Das folgende Beispiel zeigt, wie die Streuung von Daten in Java NIO durchgeführt wird
C: /Test/temp.txt
Hello World!
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ScatteringByteChannel;
public class ScatterExample {
private static String FILENAME = "C:/Test/temp.txt";
public static void main(String[] args) {
ByteBuffer bLen1 = ByteBuffer.allocate(1024);
ByteBuffer bLen2 = ByteBuffer.allocate(1024);
FileInputStream in;
try {
in = new FileInputStream(FILENAME);
ScatteringByteChannel scatter = in.getChannel();
scatter.read(new ByteBuffer[] {bLen1, bLen2});
bLen1.position(0);
bLen2.position(0);
int len1 = bLen1.asIntBuffer().get();
int len2 = bLen2.asIntBuffer().get();
System.out.println("Scattering : Len1 = " + len1);
System.out.println("Scattering : Len2 = " + len2);
}
catch (FileNotFoundException exObj) {
exObj.printStackTrace();
}
catch (IOException ioObj) {
ioObj.printStackTrace();
}
}
}
Ausgabe
Scattering : Len1 = 1214606444
Scattering : Len2 = 0
Zuletzt kann gefolgert werden, dass der Scatter / Gather-Ansatz in Java NIO bei ordnungsgemäßer Verwendung als optimierter und Multitasking-Ansatz eingeführt wird. Auf diese Weise können Sie die Grunzarbeit des Aufteilens der gelesenen Daten in mehrere Buckets oder des Zusammenstellens an das Betriebssystem delegieren Zweifellos spart dies Zeit und nutzt das Betriebssystem effizienter, indem Pufferkopien vermieden werden, und reduziert die Menge an Code, die zum Schreiben und Debuggen benötigt wird.
Da wir wissen, dass Java NIO im Vergleich zur herkömmlichen E / A-API von Java eine optimierte API für Daten-E / A-Operationen ist. Eine weitere zusätzliche Unterstützung, die Java NIO bietet, ist das Lesen / Schreiben von Daten von / zu mehreren Puffern in den Kanal Die Schreibunterstützung wird als Scatter and Gather bezeichnet, bei der Daten bei Lesedaten von einem Kanal auf mehrere Puffer gestreut werden, während bei Schreibdaten Daten von mehreren Puffern auf einen einzelnen Kanal gesammelt werden.
Um dieses mehrfache Lesen und Schreiben vom Kanal zu erreichen, gibt es die ScatteringByteChannel- und GatheringByteChannel-API, die Java NIO zum Lesen und Schreiben der Daten bereitstellt, wie im folgenden Beispiel dargestellt.
GatheringByteChannel
write to multiple channels - In diesem Fall haben wir Daten aus mehreren Puffern in einen einzelnen Kanal geschrieben. Dazu werden wiederum mehrere Puffer zugewiesen und einem Puffertyp-Array hinzugefügt. Dann wird dieses Array als Parameter an die Methode GatheringByteChannel write () übergeben, die dann Daten schreibt Aus den mehreren Puffern in der Sequenz treten die Puffer im Array auf. Ein Punkt, an den Sie sich erinnern sollten, ist, dass nur die Daten zwischen der Position und der Grenze der Puffer geschrieben werden.
Das folgende Beispiel zeigt, wie die Datenerfassung in Java NIO durchgeführt wird
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.GatheringByteChannel;
public class GatherExample {
private static String FILENAME = "C:/Test/temp.txt";
public static void main(String[] args) {
String stream1 = "Gather data stream first";
String stream2 = "Gather data stream second";
ByteBuffer bLen1 = ByteBuffer.allocate(1024);
ByteBuffer bLen2 = ByteBuffer.allocate(1024);
// Next two buffer hold the data we want to write
ByteBuffer bstream1 = ByteBuffer.wrap(stream1.getBytes());
ByteBuffer bstream2 = ByteBuffer.wrap(stream2.getBytes());
int len1 = stream1.length();
int len2 = stream2.length();
// Writing length(data) to the Buffer
bLen1.asIntBuffer().put(len1);
bLen2.asIntBuffer().put(len2);
System.out.println("Gathering : Len1 = " + len1);
System.out.println("Gathering : Len2 = " + len2);
// Write data to the file
try {
FileOutputStream out = new FileOutputStream(FILENAME);
GatheringByteChannel gather = out.getChannel();
gather.write(new ByteBuffer[] {bLen1, bLen2, bstream1, bstream2});
out.close();
gather.close();
}
catch (FileNotFoundException exObj) {
exObj.printStackTrace();
}
catch(IOException ioObj) {
ioObj.printStackTrace();
}
}
}
Ausgabe
Gathering : Len1 = 24
Gathering : Len2 = 25
Zuletzt kann gefolgert werden, dass der Scatter / Gather-Ansatz in Java NIO bei ordnungsgemäßer Verwendung als optimierter und Multitasking-Ansatz eingeführt wird. Auf diese Weise können Sie die Grunzarbeit des Aufteilens der gelesenen Daten in mehrere Buckets oder des Zusammenstellens an das Betriebssystem delegieren Zweifellos spart dies Zeit und nutzt das Betriebssystem effizienter, indem Pufferkopien vermieden werden, und reduziert die Menge an Code, die zum Schreiben und Debuggen benötigt wird.
Puffer in Java NIO können als einfaches Objekt behandelt werden, das als Container mit fester Größe von Datenblöcken fungiert, mit denen Daten in den Kanal geschrieben oder Daten aus dem Kanal gelesen werden können, sodass Puffer als Endpunkte für die Kanäle fungieren.
Es bietet eine Reihe von Methoden, die den Umgang mit Speicherblöcken zum Lesen und Schreiben von Daten zu und von Kanälen vereinfachen.
Durch Puffer wird das NIO-Paket im Vergleich zu klassischen E / A effizienter und schneller, da bei E / A-Daten Datenströme in Form von Streams verarbeitet werden, die keinen asynchronen und gleichzeitigen Datenfluss unterstützen. Außerdem ermöglicht E / A keine Datenausführung in Blöcken oder Bytegruppen .
Primärparameter, die den Java NIO-Puffer definieren, können wie folgt definiert werden:
Capacity - Maximale Datenmenge / Byte, die im Puffer gespeichert werden kann. Die Kapazität eines Puffers kann nicht geändert werden. Sobald der Puffer voll ist, sollte er vor dem Schreiben gelöscht werden.
Limit - Limit hat eine Bedeutung gemäß dem Puffermodus, dh im Schreibmodus von Buffer Limit ist gleich der Kapazität, was bedeutet, dass die maximale Datenmenge im Puffer geschrieben werden kann. Im Lesemodus des Puffers bedeutet Limit das Limit, wie viele Daten sein können aus dem Puffer lesen.
Position - Zeigt auf die aktuelle Position des Cursors im Puffer. Zum Zeitpunkt der Erstellung des Puffers wurde er zunächst auf 0 gesetzt. Mit anderen Worten, der Index des nächsten zu lesenden oder zu schreibenden Elements wird automatisch durch get () und put (aktualisiert) ) Methoden.
Mark - Markieren Sie ein Lesezeichen der Position in einem Puffer. Wenn die Methode mark () aufgerufen wird, wird die aktuelle Position aufgezeichnet, und wenn reset () aufgerufen wird, wird die markierte Position wiederhergestellt.
Puffertyp
Java NIO-Puffer können anhand der Datentypen, mit denen sich der Puffer befasst, in folgende Varianten eingeteilt werden:
- ByteBuffer
- MappedByteBuffer
- CharBuffer
- DoubleBuffer
- FloatBuffer
- IntBuffer
- LongBuffer
- ShortBuffer
Wichtige Methoden des Puffers
Wie bereits erwähnt, fungiert Buffer als Speicherobjekt, das eine Reihe von Methoden bereitstellt, die den Umgang mit Speicherblöcken erleichtern. Im Folgenden sind die wichtigen Methoden von Buffer - aufgeführt.
allocate(int capacity) - Diese Methode wird verwendet, um einen neuen Puffer mit der Kapazität als Parameter zuzuweisen. Die Allocate-Methode löst eine IllegalArgumentException aus, falls die übergebene Kapazität eine negative Ganzzahl ist.
read() and put() - Die Lesemethode des Kanals wird verwendet, um Daten von Kanal zu Puffer zu schreiben, während put eine Puffermethode ist, die zum Schreiben von Daten in den Puffer verwendet wird.
flip() - Die Flip-Methode schaltet den Puffermodus vom Schreiben in den Lesemodus um. Außerdem wird die Position auf 0 zurückgesetzt und die Grenze auf die Position zum Zeitpunkt des Schreibens festgelegt.
write() and get() - Die Schreibmethode des Kanals wird verwendet, um Daten von Puffer zu Kanal zu schreiben, während get eine Puffermethode ist, die zum Lesen von Daten aus dem Puffer verwendet wird.
rewind() - Die Rückspulmethode wird verwendet, wenn ein erneutes Lesen erforderlich ist, da die Position auf Null zurückgesetzt wird und der Grenzwert nicht geändert wird.
clear() and compact() - beide Methoden werden klar und kompakt verwendet, um den Puffer vom Lese- in den Schreibmodus zu versetzen.clear() Methode macht die Position auf Null und Limit gleich Kapazität, bei dieser Methode werden die Daten im Puffer nicht gelöscht, nur die Marker werden neu initialisiert.
Andererseits compact() Die Methode wird verwendet, wenn noch einige nicht gelesene Daten vorhanden sind und wir dennoch den Schreibmodus des Puffers verwenden. In diesem Fall kopiert die kompakte Methode alle ungelesenen Daten an den Anfang des Puffers und setzt die Position direkt nach dem letzten ungelesenen Element. Die Eigenschaft limit ist weiterhin auf Kapazität eingestellt.
mark() and reset() - Wie der Name schon sagt, wird die Markierungsmethode verwendet, um eine bestimmte Position in einem Puffer zu markieren, während die Position zum Zurücksetzen auf die markierte Position zurückgesetzt wird.
Beispiel
Das folgende Beispiel zeigt die Implementierung der oben definierten Methoden.
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
public class BufferDemo {
public static void main (String [] args) {
//allocate a character type buffer.
CharBuffer buffer = CharBuffer.allocate(10);
String text = "bufferDemo";
System.out.println("Input text: " + text);
for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
//put character in buffer.
buffer.put(c);
}
int buffPos = buffer.position();
System.out.println("Position after data is written into buffer: " + buffPos);
buffer.flip();
System.out.println("Reading buffer contents:");
while (buffer.hasRemaining()) {
System.out.println(buffer.get());
}
//set the position of buffer to 5.
buffer.position(5);
//sets this buffer's mark at its position
buffer.mark();
//try to change the position
buffer.position(6);
//calling reset method to restore to the position we marked.
//reset() raise InvalidMarkException if either the new position is less
//than the position marked or merk has not been setted.
buffer.reset();
System.out.println("Restored buffer position : " + buffer.position());
}
}
Ausgabe
Input text: bufferDemo
Position after data is written into buffer: 10
Reading buffer contents:
b
u
f
f
e
r
D
e
m
o
Restored buffer position : 5
Wie wir wissen, unterstützt Java NIO mehrere Transaktionen von und zu Kanälen und Puffern. Um einen oder mehrere NIO-Kanäle zu untersuchen und festzustellen, welche Kanäle für Datentransaktionen bereit sind, dh Java NIO lesen oder schreiben, stellen Sie Selector bereit.
Mit Selector können wir einen Thread erstellen, um zu wissen, welcher Kanal zum Schreiben und Lesen von Daten bereit ist und diesen bestimmten Kanal behandeln kann.
Wir können die Selektorinstanz erhalten, indem wir ihre statische Methode aufrufen open()Nach dem Öffnen des Selektors müssen wir einen Kanal im nicht blockierenden Modus registrieren, der eine Instanz von SelectionKey zurückgibt.
SelectionKey ist im Grunde eine Sammlung von Operationen, die mit dem Kanal ausgeführt werden können, oder wir können sagen, dass wir den Status des Kanals mithilfe des Auswahlschlüssels kennen könnten.
Die Hauptoperationen oder der Status des Kanals, der durch die Auswahltaste dargestellt wird, sind -
SelectionKey.OP_CONNECT - Kanal, der bereit ist, eine Verbindung zum Server herzustellen.
SelectionKey.OP_ACCEPT - Kanal, der bereit ist, eingehende Verbindungen anzunehmen.
SelectionKey.OP_READ - Kanal, der zum Lesen der Daten bereit ist.
SelectionKey.OP_WRITE - Kanal, der zum Schreiben von Daten bereit ist.
Der nach der Registrierung erhaltene Auswahlschlüssel hat einige wichtige Methoden, wie unten erwähnt -
attach() - Diese Methode wird verwendet, um ein Objekt mit dem Schlüssel anzuhängen. Der Hauptzweck des Anhängens eines Objekts an einen Kanal besteht darin, denselben Kanal zu erkennen.
attachment() - Diese Methode wird verwendet, um das angehängte Objekt vom Kanal fernzuhalten.
channel() - Diese Methode wird verwendet, um den Kanal abzurufen, für den der bestimmte Schlüssel erstellt wurde.
selector() - Mit dieser Methode wird der Selektor abgerufen, für den der jeweilige Schlüssel erstellt wurde.
isValid() - Diese Methode gibt zurück, ob der Schlüssel gültig ist oder nicht.
isReadable() - Diese Methode gibt an, dass der Kanal des Wetterschlüssels zum Lesen bereit ist oder nicht.
isWritable() - Diese Methode gibt an, dass der Kanal des Wetterschlüssels zum Schreiben bereit ist oder nicht.
isAcceptable() - Diese Methode gibt an, dass der Kanal des Wetterschlüssels bereit ist, eingehende Verbindungen zu akzeptieren oder nicht.
isConnectable() - Diese Methode testet, ob der Kanal dieses Schlüssels seinen Socket-Verbindungsvorgang beendet oder nicht beendet hat.
isAcceptable() - Diese Methode testet, ob der Kanal dieses Schlüssels bereit ist, eine neue Socket-Verbindung zu akzeptieren.
interestOps() - Diese Methode ruft den Interessensatz dieses Schlüssels ab.
readyOps() - Diese Methode ruft den Ready-Satz ab, für den der Kanal bereit ist.
Wir können einen Kanal aus dem Selektor auswählen, indem wir seine statische Methode aufrufen select()Die Auswahlmethode des Selektors ist überladen als -
select() - Diese Methode blockiert den aktuellen Thread, bis mindestens ein Kanal für die Ereignisse bereit ist, für die er registriert ist.
select(long timeout) - Diese Methode funktioniert genauso wie select (), außer dass der Thread für maximal Millisekunden (der Parameter) blockiert wird.
selectNow() - Diese Methode blockiert überhaupt nicht. Sie kehrt sofort mit den bereitgestellten Kanälen zurück.
Auch um einen blockierten Thread zu hinterlassen, der die Auswahlmethode aufruft,wakeup() Die Methode kann von der Selektorinstanz aus aufgerufen werden. Danach kehrt der in select () wartende Thread sofort zurück.
Zuletzt können wir den Selektor durch Aufrufen schließen close() Methode, die auch alle bei diesem Selector registrierten SelectionKey-Instanzen ungültig macht und den Selector schließt.
Beispiel
import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
public class SelectorDemo {
public static void main(String[] args) throws IOException {
String demo_text = "This is a demo String";
Selector selector = Selector.open();
ServerSocketChannel serverSocket = ServerSocketChannel.open();
serverSocket.bind(new InetSocketAddress("localhost", 5454));
serverSocket.configureBlocking(false);
serverSocket.register(selector, SelectionKey.OP_ACCEPT);
ByteBuffer buffer = ByteBuffer.allocate(256);
while (true) {
selector.select();
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> iter = selectedKeys.iterator();
while (iter.hasNext()) {
SelectionKey key = iter.next();
int interestOps = key.interestOps();
System.out.println(interestOps);
if (key.isAcceptable()) {
SocketChannel client = serverSocket.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ);
}
if (key.isReadable()) {
SocketChannel client = (SocketChannel) key.channel();
client.read(buffer);
if (new String(buffer.array()).trim().equals(demo_text)) {
client.close();
System.out.println("Not accepting client messages anymore");
}
buffer.flip();
client.write(buffer);
buffer.clear();
}
iter.remove();
}
}
}
}
In Java ist NIO Pipe eine Komponente, die zum Schreiben und Lesen von Daten zwischen zwei Threads verwendet wird. Pipe besteht hauptsächlich aus zwei Kanälen, die für die Datenverbreitung verantwortlich sind.
Unter zwei konstituierenden Kanälen wird einer als Sink-Kanal bezeichnet, der hauptsächlich zum Schreiben von Daten dient, und der andere ist der Quellkanal, dessen Hauptzweck darin besteht, Daten vom Sink-Kanal zu lesen.
Die Datensynchronisation wird während des Schreibens und Lesens der Daten in Ordnung gehalten, da sichergestellt werden muss, dass die Daten in derselben Reihenfolge gelesen werden, in der sie in die Pipe geschrieben werden.
Es muss beachtet werden, dass es sich um einen unidirektionalen Datenfluss in Pipe handelt, dh Daten werden nur im Sink-Kanal geschrieben und können nur vom Quellkanal gelesen werden.
In Java wird NIO Pipe als abstrakte Klasse mit hauptsächlich drei Methoden definiert, von denen zwei abstrakt sind.
Methoden der Rohrklasse
open() - Diese Methode wird verwendet, um eine Instanz von Pipe abzurufen, oder wir können sagen, dass Pipe durch Aufrufen dieser Methode erstellt wird.
sink() - Diese Methode gibt den Senkenkanal der Pipe zurück, der zum Schreiben von Daten verwendet wird, indem die Schreibmethode aufgerufen wird.
source() - Diese Methode gibt den Quellkanal der Pipe zurück, der zum Lesen von Daten verwendet wird, indem die Lesemethode aufgerufen wird.
Beispiel
Das folgende Beispiel zeigt die Implementierung der Java NIO-Pipe.
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.Pipe;
public class PipeDemo {
public static void main(String[] args) throws IOException {
//An instance of Pipe is created
Pipe pipe = Pipe.open();
// gets the pipe's sink channel
Pipe.SinkChannel skChannel = pipe.sink();
String testData = "Test Data to Check java NIO Channels Pipe.";
ByteBuffer buffer = ByteBuffer.allocate(512);
buffer.clear();
buffer.put(testData.getBytes());
buffer.flip();
//write data into sink channel.
while(buffer.hasRemaining()) {
skChannel.write(buffer);
}
//gets pipe's source channel
Pipe.SourceChannel sourceChannel = pipe.source();
buffer = ByteBuffer.allocate(512);
//write data into console
while(sourceChannel.read(buffer) > 0){
//limit is set to current position and position is set to zero
buffer.flip();
while(buffer.hasRemaining()){
char ch = (char) buffer.get();
System.out.print(ch);
}
//position is set to zero and limit is set to capacity to clear the buffer.
buffer.clear();
}
}
}
Ausgabe
Test Data to Check java NIO Channels Pipe.
Angenommen, wir haben eine Textdatei c:/test.txt, die folgenden Inhalt hat. Diese Datei wird als Eingabe für unser Beispielprogramm verwendet.
Wie der Name schon sagt, ist Pfad der bestimmte Speicherort einer Entität wie einer Datei oder eines Verzeichnisses in einem Dateisystem, sodass an diesem bestimmten Speicherort gesucht und darauf zugegriffen werden kann.
Technisch gesehen ist Path in Bezug auf Java eine Schnittstelle, die in Java NIO-Dateipaket während Java Version 7 eingeführt wurde und die Darstellung des Speicherorts in einem bestimmten Dateisystem darstellt. Da sich die Pfadschnittstelle in einem Java NIO-Paket befindet, erhält sie ihren qualifizierten Namen als Java .nio.file.Path.
Im Allgemeinen kann der Pfad einer Entität von zwei Typen sein: der absolute Pfad und der relative Pfad. Der Name beider Pfade legt nahe, dass der absolute Pfad die Standortadresse von der Wurzel zur Entität ist, in der sie sich befindet, während der relative Pfad die Standortadresse ist Dies ist relativ zu einem anderen Pfad. Path verwendet Trennzeichen in seiner Definition als "\" für Windows und "/" für Unix-Betriebssysteme.
Um die Instanz von Path zu erhalten, können wir die statische Methode der Klasse java.nio.file.Paths verwenden get()Diese Methode konvertiert eine Pfadzeichenfolge oder eine Folge von Zeichenfolgen, die beim Verbinden eine Pfadzeichenfolge bilden, in eine Pfadinstanz. Diese Methode löst auch die Laufzeit-InvalidPathException aus, wenn die übergebenen Argumente unzulässige Zeichen enthalten.
Wie oben erwähnt, wird der absolute Pfad durch Übergeben des Stammelements und der vollständigen Verzeichnisliste abgerufen, die zum Auffinden der Datei erforderlich ist. Während der relative Pfad durch Kombinieren des Basispfads mit dem relativen Pfad abgerufen werden kann. Das Abrufen beider Pfade wird im folgenden Beispiel veranschaulicht
Beispiel
package com.java.nio;
import java.io.IOException;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.file.FileSystem;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
public class PathDemo {
public static void main(String[] args) throws IOException {
Path relative = Paths.get("file2.txt");
System.out.println("Relative path: " + relative);
Path absolute = relative.toAbsolutePath();
System.out.println("Absolute path: " + absolute);
}
}
Bisher wissen wir, was eine Pfadschnittstelle ist, warum wir das brauchen und wie wir darauf zugreifen können. Jetzt würden wir wissen, welche wichtigen Methoden uns die Pfadschnittstelle bietet.
Wichtige Methoden der Pfadschnittstelle
getFileName() - Gibt das Dateisystem zurück, das dieses Objekt erstellt hat.
getName() - Gibt ein Namenselement dieses Pfads als Pfadobjekt zurück.
getNameCount() - Gibt die Anzahl der Namenselemente im Pfad zurück.
subpath() - Gibt einen relativen Pfad zurück, der eine Teilsequenz der Namenselemente dieses Pfads ist.
getParent() - Gibt den übergeordneten Pfad zurück oder null, wenn dieser Pfad keinen übergeordneten Pfad hat.
getRoot() - Gibt die Stammkomponente dieses Pfads als Pfadobjekt zurück oder null, wenn dieser Pfad keine Stammkomponente enthält.
toAbsolutePath() - Gibt ein Path-Objekt zurück, das den absoluten Pfad dieses Pfads darstellt.
toRealPath() - Gibt den tatsächlichen Pfad einer vorhandenen Datei zurück.
toFile() - Gibt ein Dateiobjekt zurück, das diesen Pfad darstellt.
normalize() - Gibt einen Pfad zurück, bei dem es sich um diesen Pfad handelt, bei dem redundante Namenselemente entfernt wurden.
compareTo(Path other) - Vergleicht zwei abstrakte Pfade lexikografisch. Diese Methode gibt Null zurück, wenn das Argument diesem Pfad entspricht, einen Wert kleiner als Null, wenn dieser Pfad lexikografisch kleiner als das Argument ist, oder einen Wert größer als Null, wenn dieser Pfad lexikografisch größer als das Argument ist .
endsWith(Path other) - Testet, ob dieser Pfad mit dem angegebenen Pfad endet. Wenn der angegebene Pfad N Elemente und keine Stammkomponente enthält und dieser Pfad N oder mehr Elemente enthält, endet dieser Pfad mit dem angegebenen Pfad, wenn die letzten N Elemente jedes Pfads. beginnend mit dem Element, das am weitesten von der Wurzel entfernt ist, sind sie gleich.
endsWith(String other) - Testet, ob dieser Pfad mit einem Pfad endet, der durch Konvertieren der angegebenen Pfadzeichenfolge genau in der von der Methode "EndsWith (Path)" angegebenen Weise erstellt wurde.
Beispiel
Das folgende Beispiel zeigt die verschiedenen Methoden der Pfadschnittstelle, die oben erwähnt wurden:
package com.java.nio;
import java.io.IOException;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.file.FileSystem;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
public class PathDemo {
public static void main(String[] args) throws IOException {
Path path = Paths.get("D:/workspace/ContentW/Saurav_CV.docx");
FileSystem fs = path.getFileSystem();
System.out.println(fs.toString());
System.out.println(path.isAbsolute());
System.out.println(path.getFileName());
System.out.println(path.toAbsolutePath().toString());
System.out.println(path.getRoot());
System.out.println(path.getParent());
System.out.println(path.getNameCount());
System.out.println(path.getName(0));
System.out.println(path.subpath(0, 2));
System.out.println(path.toString());
System.out.println(path.getNameCount());
Path realPath = path.toRealPath(LinkOption.NOFOLLOW_LINKS);
System.out.println(realPath.toString());
String originalPath = "d:\\data\\projects\\a-project\\..\\another-project";
Path path1 = Paths.get(originalPath);
Path path2 = path1.normalize();
System.out.println("path2 = " + path2);
}
}
Das Java NIO-Paket bietet eine weitere Dienstprogramm-API mit dem Namen "Dateien", die im Wesentlichen zum Bearbeiten von Dateien und Verzeichnissen mithilfe ihrer statischen Methoden verwendet wird, die hauptsächlich für Path-Objekte funktionieren.
Wie im Pfad-Tutorial erwähnt, wird die Pfadschnittstelle im Java NIO-Paket während der Java 7-Version im Dateipaket eingeführt. Dieses Tutorial gilt also für dasselbe Dateipaket.
Diese Klasse besteht ausschließlich aus statischen Methoden, die mit Dateien, Verzeichnissen oder anderen Dateitypen arbeiten. In den meisten Fällen werden die hier definierten Methoden an den zugeordneten Dateisystemanbieter delegiert, um die Dateivorgänge auszuführen.
In der Files-Klasse sind viele Methoden definiert, die auch aus Java-Dokumenten gelesen werden können. In diesem Lernprogramm haben wir versucht, einige der wichtigen Methoden unter allen Methoden der Java NIO Files-Klasse zu behandeln.
Wichtige Methoden der Files-Klasse.
Im Folgenden sind die wichtigen Methoden aufgeführt, die in der Java NIO Files-Klasse definiert sind.
createFile(Path filePath, FileAttribute attrs) - Die Klasse "Dateien" bietet diese Methode zum Erstellen von Dateien unter Verwendung des angegebenen Pfads.
Beispiel
package com.java.nio;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class CreateFile {
public static void main(String[] args) {
//initialize Path object
Path path = Paths.get("D:file.txt");
//create file
try {
Path createdFilePath = Files.createFile(path);
System.out.println("Created a file at : "+createdFilePath);
}
catch (IOException e) {
e.printStackTrace();
}
}
}
Ausgabe
Created a file at : D:\data\file.txt
copy(InputStream in, Path target, CopyOption… options) - Diese Methode wird verwendet, um alle Bytes aus dem angegebenen Eingabestream in die angegebene Zieldatei zu kopieren und die Anzahl der gelesenen oder geschriebenen Bytes als langen Wert zurückzugeben. LinkOption für diesen Parameter mit den folgenden Werten -
COPY_ATTRIBUTES - Kopieren Sie Attribute in die neue Datei, z. B. das Attribut für die zuletzt geänderte Zeit.
REPLACE_EXISTING - Ersetzen Sie eine vorhandene Datei, falls vorhanden.
NOFOLLOW_LINKS - Wenn eine Datei ein symbolischer Link ist, wird der Link selbst und nicht das Ziel des Links kopiert.
Beispiel
package com.java.nio;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.List;
public class WriteFile {
public static void main(String[] args) {
Path sourceFile = Paths.get("D:file.txt");
Path targetFile = Paths.get("D:fileCopy.txt");
try {
Files.copy(sourceFile, targetFile,
StandardCopyOption.REPLACE_EXISTING);
}
catch (IOException ex) {
System.err.format("I/O Error when copying file");
}
Path wiki_path = Paths.get("D:fileCopy.txt");
Charset charset = Charset.forName("ISO-8859-1");
try {
List<String> lines = Files.readAllLines(wiki_path, charset);
for (String line : lines) {
System.out.println(line);
}
}
catch (IOException e) {
System.out.println(e);
}
}
}
Ausgabe
To be or not to be?
createDirectories(Path dir, FileAttribute<?>...attrs) - Mit dieser Methode werden Verzeichnisse unter Verwendung des angegebenen Pfads erstellt, indem alle nicht vorhandenen übergeordneten Verzeichnisse erstellt werden.
delete(Path path) - Diese Methode wird verwendet, um die Datei aus dem angegebenen Pfad zu löschen. Sie löst NoSuchFileException aus, wenn die Datei nicht im angegebenen Pfad vorhanden ist oder wenn die Datei ein Verzeichnis ist und möglicherweise nicht leer ist und nicht gelöscht werden kann.
exists(Path path) - Mit dieser Methode wird überprüft, ob die Datei am angegebenen Pfad vorhanden ist. Wenn die Datei vorhanden ist, wird true oder false zurückgegeben.
readAllBytes(Path path) - Diese Methode wird verwendet, um alle Bytes aus der Datei unter dem angegebenen Pfad zu lesen und das Byte-Array zurückzugeben, das die aus der Datei gelesenen Bytes enthält.
Beispiel
package com.java.nio;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
public class ReadFile {
public static void main(String[] args) {
Path wiki_path = Paths.get("D:file.txt");
Charset charset = Charset.forName("ISO-8859-1");
try {
List<String> lines = Files.readAllLines(wiki_path, charset);
for (String line : lines) {
System.out.println(line);
}
}
catch (IOException e) {
System.out.println(e);
}
}
}
Ausgabe
Welcome to file.
size(Path path) - Diese Methode wird verwendet, um die Größe der Datei am angegebenen Pfad in Bytes abzurufen.
write(Path path, byte[] bytes, OpenOption… options) - Diese Methode wird verwendet, um Bytes unter dem angegebenen Pfad in eine Datei zu schreiben.
Beispiel
package com.java.nio;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
public class WriteFile {
public static void main(String[] args) {
Path path = Paths.get("D:file.txt");
String question = "To be or not to be?";
Charset charset = Charset.forName("ISO-8859-1");
try {
Files.write(path, question.getBytes());
List<String> lines = Files.readAllLines(path, charset);
for (String line : lines) {
System.out.println(line);
}
}
catch (IOException e) {
System.out.println(e);
}
}
}
Ausgabe
To be or not to be?
Da wir wissen, dass Java NIO Parallelität und Multithreading unterstützt, wodurch wir gleichzeitig mit verschiedenen Kanälen arbeiten können. Die API, die im Java NIO-Paket dafür verantwortlich ist, ist AsynchronousFileChannel, das unter NIO-Kanalpaket definiert ist für AsynchronousFileChannel ist java.nio.channels.AsynchronousFileChannel.
AsynchronousFileChannel ähnelt dem FileChannel des NIO, mit der Ausnahme, dass dieser Kanal die asynchrone Ausführung von Dateivorgängen ermöglicht, im Gegensatz zu synchronen E / A-Vorgängen, bei denen ein Thread eine Aktion ausführt und wartet, bis die Anforderung abgeschlossen ist. Daher können asynchrone Kanäle sicher verwendet werden durch mehrere gleichzeitige Threads.
Asynchron wird die Anforderung per Thread an den Kernel des Betriebssystems übergeben, um sie auszuführen, während der Thread weiterhin einen anderen Job verarbeitet. Sobald der Job des Kernels erledigt ist, signalisiert er dem Thread, dann bestätigt der Thread das Signal und unterbricht den aktuellen Job und verarbeitet den E / A-Job nach Bedarf.
Um Parallelität zu erreichen, bietet dieser Kanal zwei Ansätze, darunter einen als Rückgabe von a java.util.concurrent.Future object und eine andere ist das Übergeben eines Objekts vom Typ an die Operation java.nio.channels.CompletionHandler.
Wir werden beide Ansätze anhand von Beispielen einzeln verstehen.
Future Object - In diesem Fall wird eine Instanz von Future Interface vom Kanal zurückgegeben. In Future Interface gibt es get() Methode, die den Status der Operation zurückgibt, die asynchron behandelt wird, auf deren Grundlage eine weitere Ausführung einer anderen Aufgabe entschieden werden könnte. Wir können auch überprüfen, ob die Aufgabe abgeschlossen ist oder nicht, indem wir ihre aufrufen isDone Methode.
Beispiel
Das folgende Beispiel zeigt, wie das Future-Objekt verwendet und asynchrone Aufgaben ausgeführt werden.
package com.java.nio;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
public class FutureObject {
public static void main(String[] args) throws Exception {
readFile();
}
private static void readFile() throws IOException, InterruptedException, ExecutionException {
String filePath = "D:fileCopy.txt";
printFileContents(filePath);
Path path = Paths.get(filePath);
AsynchronousFileChannel channel =AsynchronousFileChannel.open(path, StandardOpenOption.READ);
ByteBuffer buffer = ByteBuffer.allocate(400);
Future<Integer> result = channel.read(buffer, 0); // position = 0
while (! result.isDone()) {
System.out.println("Task of reading file is in progress asynchronously.");
}
System.out.println("Reading done: " + result.isDone());
System.out.println("Bytes read from file: " + result.get());
buffer.flip();
System.out.print("Buffer contents: ");
while (buffer.hasRemaining()) {
System.out.print((char) buffer.get());
}
System.out.println(" ");
buffer.clear();
channel.close();
}
private static void printFileContents(String path) throws IOException {
FileReader fr = new FileReader(path);
BufferedReader br = new BufferedReader(fr);
String textRead = br.readLine();
System.out.println("File contents: ");
while (textRead != null) {
System.out.println(" " + textRead);
textRead = br.readLine();
}
fr.close();
br.close();
}
}
Ausgabe
File contents:
To be or not to be?
Task of reading file is in progress asynchronously.
Task of reading file is in progress asynchronously.
Reading done: true
Bytes read from file: 19
Buffer contents: To be or not to be?
Completion Handler - -
Dieser Ansatz ist ziemlich einfach, da wir hier die CompletionHandler-Schnittstelle verwenden und die beiden Methoden überschreiben, die eine ist completed() Methode, die aufgerufen wird, wenn die E / A-Operation erfolgreich abgeschlossen wurde und andere ist failed() Methode, die aufgerufen wird, wenn die E / A-Operationen fehlschlagen. Hierbei wird ein Handler erstellt, um das Ergebnis einer asynchronen E / A-Operation zu verarbeiten, da nach Abschluss einer Aufgabe nur der Handler Funktionen hat, die ausgeführt werden.
Beispiel
Das folgende Beispiel zeigt, wie Sie mit CompletionHandler asynchrone Aufgaben ausführen.
package com.java.nio;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.channels.CompletionHandler;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class CompletionHandlerDemo {
public static void main (String [] args) throws Exception {
writeFile();
}
private static void writeFile() throws IOException {
String input = "Content to be written to the file.";
System.out.println("Input string: " + input);
byte [] byteArray = input.getBytes();
ByteBuffer buffer = ByteBuffer.wrap(byteArray);
Path path = Paths.get("D:fileCopy.txt");
AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE);
CompletionHandler handler = new CompletionHandler() {
@Override
public void completed(Object result, Object attachment) {
System.out.println(attachment + " completed and " + result + " bytes are written.");
}
@Override
public void failed(Throwable exc, Object attachment) {
System.out.println(attachment + " failed with exception:");
exc.printStackTrace();
}
};
channel.write(buffer, 0, "Async Task", handler);
channel.close();
printFileContents(path.toString());
}
private static void printFileContents(String path) throws IOException {
FileReader fr = new FileReader(path);
BufferedReader br = new BufferedReader(fr);
String textRead = br.readLine();
System.out.println("File contents: ");
while (textRead != null) {
System.out.println(" " + textRead);
textRead = br.readLine();
}
fr.close();
br.close();
}
}
Ausgabe
Input string: Content to be written to the file.
Async Task completed and 34 bytes are written.
File contents:
Content to be written to the file.
In Java gibt es für jedes Zeichen eine genau definierte Unicode-Codeeinheit, die intern von JVM verarbeitet wird. Das Java NIO-Paket definiert eine abstrakte Klasse namens Charset, die hauptsächlich zum Codieren und Decodieren von Zeichensatz und UNICODE verwendet wird.
Standard-Zeichensätze
Die unterstützten Zeichensätze in Java sind unten angegeben.
US-ASCII - Sieben-Bit-ASCII-Zeichen.
ISO-8859-1 - Lateinisches ISO-Alphabet.
UTF-8 - Dies ist ein 8-Bit-UCS-Transformationsformat.
UTF-16BE - Dies ist ein 16-Bit-UCS-Transformationsformat mit Big-Endian-Bytereihenfolge.
UTF-16LE - Dies ist eine 16-Bit-UCS-Transformation mit kleiner Endian-Bytereihenfolge.
UTF-16 - 16-Bit-UCS-Transformationsformat.
Wichtige Methoden der Zeichensatzklasse
forName() - Diese Methode erstellt ein Zeichensatzobjekt für den angegebenen Zeichensatznamen. Der Name kann kanonisch oder ein Alias sein.
displayName() - Diese Methode gibt den kanonischen Namen eines bestimmten Zeichensatzes zurück.
canEncode() - Diese Methode prüft, ob der angegebene Zeichensatz die Codierung unterstützt oder nicht.
decode() - Diese Methode decodiert die Zeichenfolge eines bestimmten Zeichensatzes in einen Zeichenpuffer des Unicode-Zeichensatzes.
encode() - Diese Methode codiert den Zeichenpuffer des Unicode-Zeichensatzes in den Bytepuffer des angegebenen Zeichensatzes.
Beispiel
Das folgende Beispiel zeigt wichtige Methoden der Zeichensatzklasse.
package com.java.nio;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
public class CharsetExample {
public static void main(String[] args) {
Charset charset = Charset.forName("US-ASCII");
System.out.println(charset.displayName());
System.out.println(charset.canEncode());
String str = "Demo text for conversion.";
//convert byte buffer in given charset to char buffer in unicode
ByteBuffer byteBuffer = ByteBuffer.wrap(str.getBytes());
CharBuffer charBuffer = charset.decode(byteBuffer);
//convert char buffer in unicode to byte buffer in given charset
ByteBuffer newByteBuffer = charset.encode(charBuffer);
while(newbb.hasRemaining()){
char ch = (char) newByteBuffer.get();
System.out.print(ch);
}
newByteBuffer.clear();
}
}
Ausgabe
US-ASCII
Demo text for conversion.
Da wir wissen, dass Java NIO Parallelität und Multithreading unterstützt, wodurch es möglich ist, mit mehreren Threads umzugehen, die gleichzeitig mit mehreren Dateien arbeiten. In einigen Fällen ist es jedoch erforderlich, dass unsere Datei von keinem Thread freigegeben wird und nicht zugänglich ist.
Für eine solche Anforderung stellt NIO erneut eine API bereit, die als FileLock bezeichnet wird und zum Sperren der gesamten Datei oder eines Teils der Datei verwendet wird, sodass die Datei oder ihr Teil nicht freigegeben wird oder nicht zugänglich ist.
Um eine solche Sperre bereitzustellen oder anzuwenden, müssen wir FileChannel oder AsynchronousFileChannel verwenden, die zwei Methoden bereitstellen lock() und tryLock()Zu diesem Zweck gibt es zwei Arten von Schlössern:
Exclusive Lock - Eine exklusive Sperre verhindert, dass andere Programme eine überlappende Sperre eines der beiden Typen erhalten.
Shared Lock - Eine gemeinsam genutzte Sperre verhindert, dass andere gleichzeitig ausgeführte Programme eine überlappende exklusive Sperre erhalten, ermöglicht es ihnen jedoch, überlappende gemeinsam genutzte Sperren zu erwerben.
Methoden zum Abrufen der Sperrdatei -
lock() - Diese Methode von FileChannel oder AsynchronousFileChannel erhält eine exklusive Sperre für eine Datei, die dem angegebenen Kanal zugeordnet ist. Der Rückgabetyp dieser Methode ist FileLock, der weiter zur Überwachung der erhaltenen Sperre verwendet wird.
lock(long position, long size, boolean shared) - Diese Methode ist wiederum die überladene Methode der Sperrmethode und wird zum Sperren eines bestimmten Teils einer Datei verwendet.
tryLock() - Diese Methode gibt ein FileLock oder eine Null zurück, wenn die Sperre nicht erfasst werden konnte, und versucht, eine explizit exklusive Sperre für die Datei dieses Kanals abzurufen.
tryLock(long position, long size, boolean shared) - Diese Methode versucht, eine Sperre für den angegebenen Bereich der Datei dieses Kanals zu erhalten, der exklusiv oder vom gemeinsam genutzten Typ sein kann.
Methoden der FileLock-Klasse
acquiredBy() - Diese Methode gibt den Kanal zurück, auf dessen Dateisperre erworben wurde.
position() - Diese Methode gibt die Position innerhalb der Datei des ersten Bytes des gesperrten Bereichs zurück. Ein gesperrter Bereich muss nicht in der tatsächlich zugrunde liegenden Datei enthalten sein oder diese sogar überlappen, sodass der von dieser Methode zurückgegebene Wert die aktuelle Größe der Datei überschreiten kann.
size() - Diese Methode gibt die Größe des gesperrten Bereichs in Bytes zurück. Ein gesperrter Bereich muss nicht in der tatsächlichen zugrunde liegenden Datei enthalten sein oder diese sogar überlappen, sodass der von dieser Methode zurückgegebene Wert möglicherweise die aktuelle Größe der Datei überschreitet.
isShared() - Mit dieser Methode wird bestimmt, ob die Sperre gemeinsam genutzt wird oder nicht.
overlaps(long position,long size) - Diese Methode gibt an, ob diese Sperre den angegebenen Sperrbereich überlappt.
isValid() - Diese Methode gibt an, ob die erhaltene Sperre gültig ist oder nicht. Ein Sperrobjekt bleibt gültig, bis es freigegeben oder der zugehörige Dateikanal geschlossen wird, je nachdem, was zuerst eintritt.
release()- Gibt die erhaltene Sperre frei. Wenn das Sperrobjekt gültig ist, wird durch Aufrufen dieser Methode die Sperre aufgehoben und das Objekt ungültig. Wenn dieses Sperrobjekt ungültig ist, hat das Aufrufen dieser Methode keine Auswirkung.
close()- Diese Methode ruft die release () -Methode auf. Es wurde der Klasse hinzugefügt, damit es in Verbindung mit dem automatischen Ressourcenverwaltungsblockkonstrukt verwendet werden kann.
Beispiel zur Demonstration der Dateisperre.
Im folgenden Beispiel erstellen Sie eine Sperre für eine Datei und schreiben Inhalte in diese
package com.java.nio;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class FileLockExample {
public static void main(String[] args) throws IOException {
String input = "Demo text to be written in locked mode.";
System.out.println("Input string to the test file is: " + input);
ByteBuffer buf = ByteBuffer.wrap(input.getBytes());
String fp = "D:file.txt";
Path pt = Paths.get(fp);
FileChannel channel = FileChannel.open(pt, StandardOpenOption.WRITE,StandardOpenOption.APPEND);
channel.position(channel.size() - 1); // position of a cursor at the end of file
FileLock lock = channel.lock();
System.out.println("The Lock is shared: " + lock.isShared());
channel.write(buf);
channel.close(); // Releases the Lock
System.out.println("Content Writing is complete. Therefore close the channel and release the lock.");
PrintFileCreated.print(fp);
}
}
package com.java.nio;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class PrintFileCreated {
public static void print(String path) throws IOException {
FileReader filereader = new FileReader(path);
BufferedReader bufferedreader = new BufferedReader(filereader);
String tr = bufferedreader.readLine();
System.out.println("The Content of testout.txt file is: ");
while (tr != null) {
System.out.println(" " + tr);
tr = bufferedreader.readLine();
}
filereader.close();
bufferedreader.close();
}
}
Ausgabe
Input string to the test file is: Demo text to be written in locked mode.
The Lock is shared: false
Content Writing is complete. Therefore close the channel and release the lock.
The Content of testout.txt file is:
To be or not to be?Demo text to be written in locked mode.