Java NIO - Guide rapide
Le package Java.nio a été introduit dans java 1.4. Contrairement aux E / S java dans java NIO, le flux de données orienté tampon et canal pour les opérations d'E / S est introduit, ce qui permet une exécution plus rapide et de meilleures performances.
NIO API propose également des sélecteurs qui introduisent la fonctionnalité d'écoute de plusieurs canaux pour les événements d'E / S de manière asynchrone ou non bloquante.Dans NIO, les activités d'E / S les plus chronophages, y compris le remplissage et la vidange des tampons vers le système d'exploitation, ce qui augmente en vitesse.
Les abstractions centrales des API NIO sont les suivantes:
Les tampons, qui sont des conteneurs pour les données, les jeux de caractères et leurs décodeurs et encodeurs associés, qui traduisent entre les octets et les caractères Unicode.
Canaux de différents types, qui représentent des connexions à des entités capables d'effectuer des opérations d'E / S
Sélecteurs et touches de sélection qui, avec les canaux sélectionnables, définissent une fonction d'E / S multiplexée et non bloquante.
Cette section vous explique comment télécharger et configurer Java sur votre machine. Veuillez suivre les étapes suivantes pour configurer l'environnement.
Java SE est disponible gratuitement à partir du lien Télécharger Java . Vous téléchargez donc une version basée sur votre système d'exploitation.
Suivez les instructions pour télécharger java et exécuter le .exepour installer Java sur votre machine. Une fois que vous avez installé Java sur votre machine, vous devez définir des variables d'environnement pour qu'elles pointent vers les répertoires d'installation corrects -
Configuration du chemin pour Windows 2000 / XP
En supposant que vous ayez installé Java dans le répertoire c: \ Program Files \ java \ jdk -
Cliquez avec le bouton droit sur «Poste de travail» et sélectionnez «Propriétés».
Cliquez sur le bouton «Variables d'environnement» sous l'onglet «Avancé».
Modifiez maintenant la variable «Path» afin qu'elle contienne également le chemin d'accès à l'exécutable Java. Exemple, si le chemin est actuellement défini sur «C: \ WINDOWS \ SYSTEM32», modifiez votre chemin pour lire «C: \ WINDOWS \ SYSTEM32; c: \ Program Files \ java \ jdk \ bin».
Configuration du chemin pour Windows 95/98 / ME
En supposant que vous ayez installé Java dans le répertoire c: \ Program Files \ java \ jdk -
Modifiez le fichier 'C: \ autoexec.bat' et ajoutez la ligne suivante à la fin:
'SET PATH =% PATH%; C: \ Program Files \ java \ jdk \ bin'
Configuration du chemin pour Linux, UNIX, Solaris, FreeBSD
La variable d'environnement PATH doit être définie pour pointer vers l'endroit où les binaires Java ont été installés. Reportez-vous à la documentation de votre shell si vous rencontrez des problèmes pour cela.
Exemple, si vous utilisez bash comme shell, vous ajouteriez la ligne suivante à la fin de votre '.bashrc: export PATH = / path / to / java: $ PATH'
Éditeurs Java populaires
Pour écrire vos programmes java, vous aurez besoin d'un éditeur de texte. Il existe des IDE encore plus sophistiqués disponibles sur le marché. Mais pour l'instant, vous pouvez envisager l'un des éléments suivants -
Notepad - Sur la machine Windows, vous pouvez utiliser n'importe quel éditeur de texte simple comme Notepad (recommandé pour ce tutoriel), TextPad.
Netbeans - est un IDE Java open source et gratuit qui peut être téléchargé depuis http://www.netbeans.org/index.html.
Eclipse - est également un IDE Java développé par la communauté open source eclipse et peut être téléchargé depuis https://www.eclipse.org/.
Comme nous le savons, java NIO est introduit pour l'avancement de l'API Java IO conventionnelle.Les principales améliorations qui rendent NIO plus efficace que IO sont le modèle de flux de données de canal utilisé dans NIO et l'utilisation du système d'exploitation pour les tâches IO conventionnelles.
La différence entre Java NIO et Java IO peut être expliquée comme suit:
Comme mentionné dans l'article précédent dans la mémoire tampon NIO et le flux de données orienté canal pour les opérations d'E / S qui offrent une exécution plus rapide et de meilleures performances par rapport à IO.NIO utilise également le système d'exploitation pour les tâches d'E / S conventionnelles, ce qui le rend encore plus efficace.
Un autre aspect de la différence entre NIO et IO est que cette IO utilise un flux de données de ligne de flux, c'est-à-dire un octet de plus à la fois et repose sur la conversion des objets de données en octets et vice-versa tandis que NIO traite les blocs de données qui sont des morceaux d'octets.
En java, les objets de flux IO sont unidirectionnels tandis que dans les canaux NIO sont bidirectionnels, ce qui signifie qu'un canal peut être utilisé à la fois pour la lecture et l'écriture de données.
Le flux de données rationalisé dans IO ne permet pas d'aller et venir dans les données.Si le cas doit se déplacer d'avant en arrière dans les données lues à partir d'un flux, il faut d'abord les mettre en cache dans un tampon.Alors qu'en cas de NIO, nous utilisons le tampon orienté qui permet d'accéder aux données dans les deux sens sans avoir besoin de mise en cache.
L'API NIO prend également en charge le multi-threading afin que les données puissent être lues et écrites de manière asynchrone de manière à ne pas bloquer le thread actuel lors des opérations d'E / S, ce qui le rend encore plus efficace que l'API Java IO conventionnelle.
Le concept de multi threading est introduit avec l'introduction de Selectors en java NIO qui permettent d'écouter plusieurs canaux pour les événements IO de manière asynchrone ou non bloquante.
Le multi-threading dans NIO le rend non bloquant, ce qui signifie que le thread est invité à lire ou à écrire uniquement lorsque les données sont disponibles, sinon le thread peut être utilisé dans une autre tâche pendant le temps moyen, mais cela n'est pas possible dans le cas d'E / S Java conventionnelles car pas de multi-threading est pris en charge, ce qui en fait un blocage.
NIO permet de gérer plusieurs canaux en utilisant un seul thread, mais le coût est que l'analyse des données peut être un peu plus compliquée que lors de la lecture de données à partir d'un flux de blocage dans le cas de java IO.Donc, dans le cas où moins de connexions avec une bande passante très élevée sont nécessaires avec l'envoi de beaucoup de données à la fois, que dans ce cas, l'API java IO pourrait être la meilleure solution.
La description
Comme son nom l'indique, le canal est utilisé comme moyen de flux de données d'un bout à l'autre. Ici, dans java, le canal NIO agit de la même manière entre le tampon et une entité à l'autre extrémité, en d'autres termes, le canal est utilisé pour lire les données dans le tampon et également pour écrire les données du tampon.
Contrairement aux flux qui sont utilisés dans les canaux Java IO conventionnels, les canaux IO sont bidirectionnels, c'est-à-dire peuvent lire et écrire. Le canal Java NIO prend en charge le flux de données asynchrone en mode bloquant et non bloquant.
Implémentations de Channel
Le canal Java NIO est implémenté principalement dans les classes suivantes -
FileChannel- Afin de lire les données du fichier, nous utilisons le canal de fichier. L'objet du canal de fichier ne peut être créé qu'en appelant la méthode getChannel () sur l'objet fichier car nous ne pouvons pas créer d'objet fichier directement.
DatagramChannel - Le canal de datagramme peut lire et écrire les données sur le réseau via UDP (User Datagram Protocol). L'objet de DataGramchannel peut être créé en utilisant des méthodes d'usine.
SocketChannel- Le canal SocketChannel peut lire et écrire les données sur le réseau via TCP (Transmission Control Protocol). Il utilise également les méthodes de fabrique pour créer le nouvel objet.
ServerSocketChannel- Le ServerSocketChannel lit et écrit les données via des connexions TCP, comme un serveur Web. Pour chaque connexion entrante, un SocketChannel est créé.
Exemple
L'exemple suivant lit un fichier texte à partir de C:/Test/temp.txt et imprime le contenu sur la console.
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();
}
}
Production
Hello World!
La description
Comme déjà mentionné, l'implémentation FileChannel du canal Java NIO est introduite pour accéder aux propriétés des métadonnées du fichier, y compris la création, la modification, la taille, etc. Parallèlement à cela, les canaux de fichiers sont multithreads, ce qui rend à nouveau Java NIO plus efficace que Java IO.
En général, nous pouvons dire que FileChannel est un canal qui est connecté à un fichier par lequel vous pouvez lire des données d'un fichier et écrire des données dans un fichier.Une autre caractéristique importante de FileChannel est qu'il ne peut pas être mis en mode non bloquant et fonctionne toujours en mode de blocage.
Nous ne pouvons pas obtenir l'objet de canal de fichier directement, l'objet du canal de fichier est obtenu soit par -
getChannel() - méthode sur n'importe quel FileInputStream, FileOutputStream ou RandomAccessFile.
open() - méthode de canal de fichier qui par défaut ouvre le canal.
Le type d'objet du canal de fichier dépend du type de classe appelée depuis la création d'objet, c'est-à-dire que si l'objet est créé en appelant la méthode getchannel de FileInputStream, le canal de fichier est ouvert pour la lecture et lancera une exception NonWritableChannelException au cas où une tentative d'écrire dessus.
Exemple
L'exemple suivant montre comment lire et écrire des données à partir de Java NIO FileChannel.
L'exemple suivant lit un fichier texte à partir de C:/Test/temp.txt et imprime le contenu sur la console.
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();
}
}
Production
Hello World! Welcome to TutorialsPoint
Java NIO Datagram est utilisé comme canal qui peut envoyer et recevoir des paquets UDP via une connexion sans protocole.Par défaut, le canal de datagramme est bloquant alors qu'il peut être utilisé en mode non bloquant.Afin de le rendre non bloquant, nous pouvons utiliser le configureBlocking ( false) Le canal DataGram peut être ouvert en appelant sa méthode statique nommée comme open() qui peut également prendre l'adresse IP comme paramètre afin qu'elle puisse être utilisée pour la multi-diffusion.
Le canal de datagramme de FileChannel n'est pas connecté par défaut afin de le rendre connecté, nous devons appeler explicitement sa méthode connect () Cependant, le canal de datagramme n'a pas besoin d'être connecté pour que les méthodes d'envoi et de réception soient utilisées alors qu'il doit être connecté afin d'utiliser les méthodes de lecture et d'écriture, car ces méthodes n'acceptent ni ne retournent les adresses de socket.
Nous pouvons vérifier l'état de connexion du canal de datagramme en appelant son isConnected() Une fois connecté, un canal de datagramme reste connecté jusqu'à ce qu'il soit déconnecté ou fermé. Les canaux de diagramme sont thread-safe et prennent en charge simultanément le multi-threading et la concurrence.
Méthodes importantes de canal de datagramme
bind(SocketAddress local) - Cette méthode est utilisée pour lier la socket du canal de datagramme à l'adresse locale qui est fournie comme paramètre de cette méthode.
connect(SocketAddress remote) - Cette méthode est utilisée pour connecter la prise à l'adresse distante.
disconnect() - Cette méthode est utilisée pour déconnecter le socket de l'adresse distante.
getRemoteAddress() - Cette méthode renvoie l'adresse de l'emplacement distant auquel la prise du canal est connectée.
isConnected() - Comme déjà mentionné cette méthode retourne l'état de connexion du canal de datagramme c'est-à-dire s'il est connecté ou non.
open() and open(ProtocolFamily family) - La méthode ouverte est utilisée pour ouvrir un canal de datagramme pour une seule adresse tandis que la méthode ouverte paramétrée ouvre un canal pour plusieurs adresses représentées comme une famille de protocoles.
read(ByteBuffer dst) - Cette méthode est utilisée pour lire les données du tampon donné via le canal de datagramme.
receive(ByteBuffer dst) - Cette méthode est utilisée pour recevoir des datagrammes via ce canal.
send(ByteBuffer src, SocketAddress target) - Cette méthode est utilisée pour envoyer des datagrammes via ce canal.
Exemple
L'exemple suivant montre comment envoyer des données à partir de Java NIO DataGramChannel.
Serveur: 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();
}
}
Production
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();
}
}
Production
L'exécution du client imprimera la sortie suivante sur le serveur.
Server Started: localhost/127.0.0.1:8989
Client at /127.0.0.1:64857 sent: Hello World!
Le canal de socket Java NIO est un canal de type sélectionnable, ce qui signifie qu'il peut être multiplexé à l'aide du sélecteur, utilisé pour les sockets de connexion de flux de données orientés flux. Le canal de socket peut être créé en appelant son statique open() , à condition qu'aucune socket préexistante ne soit déjà présente.Le canal de socket est créé en invoquant la méthode ouverte mais pas encore connecté.Afin de connecter le canal de socket connect() Un point à mentionner ici est que si le canal n'est pas connecté et qu'une opération d'E / S est tentée, alors NotYetConnectedException est levée par ce canal.Il faut donc s'assurer que le canal est connecté avant d'effectuer toute IO Une fois le canal connecté, il reste connecté jusqu'à ce qu'il soit fermé. L'état du canal socket peut être déterminé en invoquant son isConnected méthode.
La connexion du canal de socket peut être terminée en invoquant son finishConnect() Le fait qu'une opération de connexion soit en cours ou non peut être déterminé en appelant la méthode isConnectionPending.Par défaut, le canal de socket prend en charge la connexion non bloquante.Il prend également en charge l'arrêt asynchrone, qui est similaire à l'opération de fermeture asynchrone spécifiée dans la classe Channel.
Les canaux de socket sont sûrs pour une utilisation par plusieurs threads simultanés. Ils prennent en charge la lecture et l'écriture simultanées, bien qu'au plus un thread puisse être en lecture et au plus un thread puisse écrire à un moment donné. Les méthodes connect et finishConnect sont mutuellement synchronisées l'une par rapport à l'autre, et une tentative d'initier une opération de lecture ou d'écriture alors qu'une invocation de l'une de ces méthodes est en cours bloquera jusqu'à ce que cet appel soit terminé.
Méthodes importantes de canal de socket
bind(SocketAddress local) - Cette méthode est utilisée pour lier le canal de socket à l'adresse locale qui est fournie comme paramètre de cette méthode.
connect(SocketAddress remote) - Cette méthode est utilisée pour connecter la prise à l'adresse distante.
finishConnect() - Cette méthode est utilisée pour terminer le processus de connexion d'un canal de socket.
getRemoteAddress() - Cette méthode renvoie l'adresse de l'emplacement distant auquel la prise du canal est connectée.
isConnected() - Comme déjà mentionné, cette méthode retourne l'état de connexion du canal de socket c'est-à-dire s'il est connecté ou non.
open() and open((SocketAddress remote) - La méthode ouverte est utilisée pour ouvrir un canal de socket pour aucune adresse spécifiée tandis que la méthode ouverte paramétrée ouvre le canal pour l'adresse distante spécifiée et s'y connecte également.Cette méthode pratique fonctionne comme si en appelant la méthode open (), en invoquant la méthode de connexion sur le résultat socket channel, en le passant à distance, puis en renvoyant ce canal.
read(ByteBuffer dst) - Cette méthode est utilisée pour lire les données du tampon donné via le canal socket.
isConnectionPending() - Cette méthode indique si une opération de connexion est en cours ou non sur ce canal.
Exemple
L'exemple suivant montre comment envoyer des données à partir de Java NIO SocketChannel.
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();
}
}
Production
L'exécution du client n'imprimera rien avant le démarrage du serveur.
Serveur: 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();
}
}
Production
L'exécution du serveur imprimera ce qui suit.
Connection Set: /127.0.0.1:49558
File Received
Le canal de socket du serveur Java NIO est à nouveau un canal de type sélectionnable utilisé pour les sockets de connexion de flux de données orienté flux.Le canal de socket serveur peut être créé en invoquant son canal statique. open() , à condition qu'aucune socket préexistante ne soit déjà présente.Le canal de socket serveur est créé en invoquant une méthode ouverte mais pas encore lié.Afin de lier le canal de socket bind() la méthode doit être appelée.
Un point à mentionner ici est que si le canal n'est pas lié et qu'une opération d'E / S est tentée, alors NotYetBoundException est levée par ce canal.Il faut donc s'assurer que le canal est borné avant d'effectuer toute opération d'E / S.
Les connexions entrantes pour le canal de socket du serveur sont écoutées en appelant la méthode ServerSocketChannel.accept (). Lorsque la méthode accept () retourne, elle renvoie un SocketChannel avec une connexion entrante. Ainsi, la méthode accept () se bloque jusqu'à ce qu'une connexion entrante arrive. Si le canal est en mode non bloquant, la méthode accept retournera immédiatement null s'il n'y a pas de connexions en attente. Sinon, il se bloquera indéfiniment jusqu'à ce qu'une nouvelle connexion soit disponible ou qu'une erreur d'E / S se produise.
Le socket du nouveau canal est initialement non lié; il doit être lié à une adresse spécifique via l'une des méthodes de liaison de son socket avant que les connexions puissent être acceptées. De plus, le nouveau canal est créé en appelant la méthode openServerSocketChannel de l'objet SelectorProvider par défaut à l'échelle du système.
Comme le canal socket, le canal socket du serveur peut lire des données en utilisant read()Le tampon est d'abord alloué. Les données lues à partir d'un ServerSocketChannel sont stockées dans le tampon. Deuxièmement, nous appelons la méthode ServerSocketChannel.read () et il lit les données d'un ServerSocketChannel dans un tampon. La valeur entière de la méthode read () renvoie le nombre d'octets écrits dans le tampon
De même, les données peuvent être écrites sur le canal de socket du serveur en utilisant write() utilisant buffer comme paramètre. Utilise couramment la méthode write dans une boucle while pour répéter la méthode write () jusqu'à ce que le Buffer n'ait plus d'octets disponibles pour écrire.
Méthodes importantes de canal de socket
bind(SocketAddress local) - Cette méthode est utilisée pour lier le canal de socket à l'adresse locale qui est fournie comme paramètre de cette méthode.
accept() - Cette méthode est utilisée pour accepter une connexion établie à la prise de ce canal.
connect(SocketAddress remote) - Cette méthode est utilisée pour connecter la prise à l'adresse distante.
finishConnect() - Cette méthode est utilisée pour terminer le processus de connexion d'un canal de socket.
getRemoteAddress() - Cette méthode renvoie l'adresse de l'emplacement distant auquel la prise du canal est connectée.
isConnected() - Comme déjà mentionné, cette méthode retourne l'état de connexion du canal de socket c'est-à-dire s'il est connecté ou non.
open() - La méthode Open est utilisée pour ouvrir un canal de socket pour aucune adresse spécifiée. Cette méthode pratique fonctionne comme en invoquant la méthode open (), en invoquant la méthode de connexion sur le canal de socket du serveur résultant, en le passant à distance, puis en renvoyant ce canal.
read(ByteBuffer dst) - Cette méthode est utilisée pour lire les données du tampon donné via le canal socket.
setOption(SocketOption<T> name, T value) - Cette méthode définit la valeur d'une option de socket.
socket() - Cette méthode récupère un socket serveur associé à ce canal.
validOps() - Cette méthode retourne un ensemble d'opérations identifiant les opérations prises en charge par ce canal. Les canaux de socket serveur ne prennent en charge que l'acceptation de nouvelles connexions, donc cette méthode retourne SelectionKey.OP_ACCEPT.
Exemple
L'exemple suivant montre comment envoyer des données à partir de Java NIO ServerSocketChannel.
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();
}
}
Production
L'exécution du client n'imprimera rien avant le démarrage du serveur.
Serveur: 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();
}
}
Production
L'exécution du serveur imprimera ce qui suit.
Connection Set: /127.0.0.1:49558
File Received
Comme nous savons que Java NIO est une API plus optimisée pour les opérations d'E / S de données par rapport à l'API IO conventionnelle de Java, une autre prise en charge supplémentaire fournie par Java NIO consiste à lire / écrire des données depuis / vers plusieurs tampons vers le canal. et le support d'écriture est appelé Scatter and Gather dans lequel les données sont dispersées vers plusieurs tampons à partir d'un seul canal en cas de lecture de données tandis que les données sont collectées à partir de plusieurs tampons vers un seul canal en cas d'écriture de données.
Afin de réaliser ces multiples lectures et écritures à partir du canal, il existe les API ScatteringByteChannel et GatheringByteChannel que Java NIO fournit pour lire et écrire les données, comme illustré dans l'exemple ci-dessous.
ScatteringByteChannel
Read from multiple channels - En cela, nous avons fait de lire les données d'un seul canal dans plusieurs tampons.Pour cela, plusieurs tampons sont alloués et ajoutés à un tableau de type tampon.Ensuite, ce tableau est passé en paramètre à la méthode ScatteringByteChannel read () qui écrit ensuite les données le canal dans la séquence où les tampons se produisent dans le tableau. Une fois qu'un tampon est plein, le canal se déplace pour remplir le tampon suivant.
L'exemple suivant montre comment la dispersion des données est effectuée dans Java NIO
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();
}
}
}
Production
Scattering : Len1 = 1214606444
Scattering : Len2 = 0
Enfin, on peut conclure que l'approche scatter / rassembler dans Java NIO est introduite comme une approche optimisée et multitâche lorsqu'elle est utilisée correctement.Elle vous permet de déléguer au système d'exploitation le travail difficile de séparer les données que vous lisez en plusieurs seaux, ou d'assembler Il ne fait aucun doute que cela permet de gagner du temps et d'utiliser le système d'exploitation plus efficacement en évitant les copies de mémoire tampon et de réduire la quantité de code nécessaire à écrire et à déboguer.
Comme nous savons que Java NIO est une API plus optimisée pour les opérations d'E / S de données par rapport à l'API IO conventionnelle de Java, une autre prise en charge supplémentaire fournie par Java NIO consiste à lire / écrire des données depuis / vers plusieurs tampons vers le canal. et le support d'écriture est appelé Scatter and Gather dans lequel les données sont dispersées vers plusieurs tampons à partir d'un seul canal en cas de lecture de données tandis que les données sont collectées à partir de plusieurs tampons vers un seul canal en cas d'écriture de données.
Afin de réaliser ces multiples lectures et écritures à partir du canal, il existe les API ScatteringByteChannel et GatheringByteChannel que Java NIO fournit pour lire et écrire les données, comme illustré dans l'exemple ci-dessous.
GatheringByteChannel
write to multiple channels - En cela, nous avons fait d'écrire des données de plusieurs tampons dans un seul canal.Pour cela, plusieurs tampons sont alloués et ajoutés à un tableau de type tampon.Ensuite, ce tableau est passé en paramètre à la méthode write () GatheringByteChannel qui écrit ensuite les données à partir des tampons multiples de la séquence, les tampons apparaissent dans le tableau. Un point à retenir ici est que seules les données entre la position et la limite des tampons sont écrites.
L'exemple suivant montre comment la collecte de données est effectuée dans Java NIO
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();
}
}
}
Production
Gathering : Len1 = 24
Gathering : Len2 = 25
Enfin, on peut conclure que l'approche scatter / rassembler dans Java NIO est introduite comme une approche optimisée et multitâche lorsqu'elle est utilisée correctement.Elle vous permet de déléguer au système d'exploitation le travail difficile de séparer les données que vous lisez en plusieurs seaux, ou d'assembler Il ne fait aucun doute que cela permet de gagner du temps et d'utiliser le système d'exploitation plus efficacement en évitant les copies de mémoire tampon et de réduire la quantité de code nécessaire à écrire et à déboguer.
Les tampons dans Java NIO peuvent être traités comme un objet simple qui agit comme un conteneur de taille fixe de blocs de données pouvant être utilisé pour écrire des données sur le canal ou lire des données à partir du canal afin que les tampons agissent comme des points de terminaison pour les canaux.
Il fournit un ensemble de méthodes qui facilitent la gestion des blocs de mémoire afin de lire et d'écrire des données vers et depuis les canaux.
Les tampons rendent le package NIO plus efficace et plus rapide par rapport aux E / S classiques, car dans le cas des données d'E / S, les données sont traitées sous la forme de flux qui ne prennent pas en charge les flux de données asynchrones et simultanés. .
Les paramètres primaires qui définissent le tampon Java NIO peuvent être définis comme suit:
Capacity - Quantité maximum de données / octet pouvant être stockées dans le tampon. La capacité d'un tampon ne peut pas être modifiée. Une fois que le tampon est plein, il doit être effacé avant d'y écrire.
Limit - La limite a une signification selon le mode de tampon, c'est-à-dire en mode d'écriture, la limite de tampon est égale à la capacité, ce qui signifie que le maximum de données pouvant être écrites dans le tampon.Tandis qu'en mode de lecture du tampon, la limite signifie la limite de la quantité de données pouvant être lire à partir du tampon.
Position - pointe vers l'emplacement actuel du curseur dans le buffer. Initialement réglé à 0 au moment de la création du buffer ou en d'autres termes c'est l'index de l'élément suivant à lire ou à écrire qui est mis à jour automatiquement par get () et put ( ) méthodes.
Mark - Marquer un signet de la position dans un tampon. Lorsque la méthode mark () est appelée, la position actuelle est enregistrée et lorsque reset () est appelé, la position marquée est restaurée.
Type de tampon
Les tampons Java NIO peuvent être classés dans les variantes suivantes sur la base des types de données traités par le tampon -
- ByteBuffer
- MappedByteBuffer
- CharBuffer
- DoubleBuffer
- FloatBuffer
- IntBuffer
- LongBuffer
- ShortBuffer
Méthodes importantes de Buffer
Comme déjà mentionné, Buffer agit comme un objet mémoire qui fournit un ensemble de méthodes qui rendent plus pratique le traitement des blocs de mémoire.Voici les méthodes importantes de Buffer -
allocate(int capacity) - Cette méthode est utilisée pour allouer un nouveau tampon avec une capacité comme paramètre. La méthode Allocate lève une exception IllegalArgumentException au cas où la capacité transmise serait un entier négatif.
read() and put() - la méthode de lecture du canal est utilisée pour écrire des données du canal vers le tampon tandis que put est une méthode du tampon qui est utilisée pour écrire des données dans le tampon.
flip() - La méthode flip fait passer le mode de Buffer du mode d'écriture au mode de lecture. Elle remet également la position à 0 et définit la limite à l'endroit où la position était au moment de l'écriture.
write() and get() - la méthode d'écriture du canal est utilisée pour écrire des données du tampon au canal tandis que get est une méthode du tampon qui est utilisée pour lire les données du tampon.
rewind() - la méthode de rembobinage est utilisée lorsqu'une relecture est nécessaire car elle remet la position à zéro et ne modifie pas la valeur de limite.
clear() and compact() - clear et compact les deux méthodes sont utilisées pour faire du tampon du mode lecture au mode écriture.clear() met la position à zéro et la limite est égale à la capacité, dans cette méthode, les données dans le tampon ne sont pas effacées, seuls les marqueurs sont réinitialisés.
D'autre part compact() méthode est utilisée lorsqu'il reste des données non lues et que nous utilisons toujours le mode d'écriture du tampon dans ce cas, la méthode compacte copie toutes les données non lues au début du tampon et définit la position juste après le dernier élément non lu. mis à la capacité.
mark() and reset() - Comme son nom l'indique, la méthode de marquage est utilisée pour marquer une position particulière dans un tampon pendant la réinitialisation de la position de retour à la position marquée.
Exemple
L'exemple suivant montre l'implémentation des méthodes définies ci-dessus.
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());
}
}
Production
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
Comme nous savons que Java NIO prend en charge plusieurs transactions depuis et vers les canaux et la mémoire tampon. Ainsi, afin d'examiner un ou plusieurs canaux NIO, et de déterminer quels canaux sont prêts pour la transaction de données, c'est-à-dire la lecture ou l'écriture de Java NIO fournit Selector.
Avec Selector, nous pouvons créer un thread pour savoir quel canal est prêt pour l'écriture et la lecture de données et pourrait traiter ce canal particulier.
Nous pouvons obtenir une instance de sélecteur en appelant sa méthode statique open().Après avoir ouvert le sélecteur, nous devons enregistrer un canal en mode non bloquant avec lui qui retourne une instance de SelectionKey.
SelectionKey est essentiellement une collection d'opérations qui peuvent être effectuées avec le canal ou nous pouvons dire que nous pourrions connaître l'état du canal à l'aide de la touche de sélection.
Les principales opérations ou l'état du canal représenté par la touche de sélection sont -
SelectionKey.OP_CONNECT - Canal prêt à se connecter au serveur.
SelectionKey.OP_ACCEPT - Canal prêt à accepter les connexions entrantes.
SelectionKey.OP_READ - Canal prêt à lire les données.
SelectionKey.OP_WRITE - Canal prêt à écrire des données.
La clé de sélection obtenue après l'enregistrement a quelques méthodes importantes comme mentionné ci-dessous -
attach() - Cette méthode est utilisée pour attacher un objet avec la clé. Le but principal de l'attachement d'un objet à un canal est de reconnaître le même canal.
attachment() - Cette méthode est utilisée pour conserver l'objet attaché du canal.
channel() - Cette méthode est utilisée pour obtenir le canal pour lequel la clé particulière est créée.
selector() - Cette méthode est utilisée pour obtenir le sélecteur pour lequel la clé particulière est créée.
isValid() - Cette méthode retourne si la clé est valide ou non.
isReadable() - Cette méthode indique que le canal de la clé météo est prêt à être lu ou non.
isWritable() - Cette méthode indique que le canal de la clé météo est prêt pour l'écriture ou non.
isAcceptable() - Cette méthode indique que le canal de la clé météo est prêt à accepter une connexion entrante ou non.
isConnectable() - Cette méthode teste si le canal de cette clé a terminé ou échoué à terminer son opération de connexion de socket.
isAcceptable() - Cette méthode teste si le canal de cette clé est prêt à accepter une nouvelle connexion socket.
interestOps() - Cette méthode récupère l'ensemble des intérêts de cette clé.
readyOps() - Cette méthode récupère l'ensemble prêt qui est l'ensemble des opérations pour lesquelles le canal est prêt.
Nous pouvons sélectionner un canal à partir du sélecteur en appelant sa méthode statique select()La méthode .Select du sélecteur est surchargée comme -
select() - Cette méthode bloque le thread actuel jusqu'à ce qu'au moins un canal soit prêt pour les événements pour lesquels il est enregistré.
select(long timeout) - Cette méthode fait la même chose que select () sauf qu'elle bloque le thread pendant un maximum de millisecondes de timeout (le paramètre).
selectNow() - Cette méthode ne bloque pas du tout, elle revient immédiatement avec les canaux prêts.
Aussi pour laisser un thread bloqué qui appelle la méthode de sélection,wakeup() La méthode peut être appelée à partir d'une instance de sélecteur, après quoi le thread en attente dans select () retournera immédiatement.
En dernier on peut fermer le sélecteur en appelant close() qui invalide également toutes les instances de SelectionKey enregistrées avec ce sélecteur tout en fermant le sélecteur.
Exemple
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();
}
}
}
}
Dans Java NIO pipe est un composant qui est utilisé pour écrire et lire des données entre deux threads.Pipe se compose principalement de deux canaux qui sont responsables de la propagation des données.
Parmi deux canaux constituants, l'un est appelé canal Sink qui est principalement destiné à l'écriture de données et l'autre est le canal Source dont le but principal est de lire les données du canal Sink.
La synchronisation des données est maintenue dans l'ordre pendant l'écriture et la lecture des données, car il faut s'assurer que les données doivent être lues dans le même ordre que celui dans lequel elles sont écrites dans le Pipe.
Il doit garder à l'esprit qu'il s'agit d'un flux de données unidirectionnel dans Pipe, c'est-à-dire que les données sont écrites dans le canal Sink uniquement et ne peuvent être lues qu'à partir du canal source.
En Java, NIO pipe est définie comme une classe abstraite avec principalement trois méthodes dont deux sont abstraites.
Méthodes de classe Pipe
open() - Cette méthode est utilisée pour obtenir une instance de Pipe ou nous pouvons dire que pipe est créée en appelant cette méthode.
sink() - Cette méthode renvoie le canal récepteur du Pipe qui est utilisé pour écrire des données en appelant sa méthode d'écriture.
source() - Cette méthode retourne le canal source du Pipe qui est utilisé pour lire les données en appelant sa méthode read.
Exemple
L'exemple suivant montre l'implémentation du canal Java NIO.
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();
}
}
}
Production
Test Data to Check java NIO Channels Pipe.
En supposant que nous ayons un fichier texte c:/test.txt, qui a le contenu suivant. Ce fichier sera utilisé comme entrée pour notre programme d'exemple.
Comme son nom l'indique, Path est l'emplacement particulier d'une entité telle qu'un fichier ou un répertoire dans un système de fichiers afin que l'on puisse le rechercher et y accéder à cet emplacement particulier.
Techniquement en termes de Java, Path est une interface qui est introduite dans le package de fichiers Java NIO pendant la version 7 de Java, et est la représentation de l'emplacement dans un système de fichiers particulier.Comme l'interface de chemin est dans le package Java NIO, il obtient son nom qualifié en java .nio.file.Path.
En général, le chemin d'une entité peut être de deux types, l'un est le chemin absolu et l'autre est le chemin relatif.Comme le nom des deux chemins suggère que le chemin absolu est l'adresse de l'emplacement de la racine à l'entité où il se trouve tandis que le chemin relatif est l'adresse de l'emplacement qui est relatif à un autre chemin. Chemin utilise des délimiteurs dans sa définition comme "\" pour Windows et "/" pour les systèmes d'exploitation Unix.
Afin d'obtenir l'instance de Path, nous pouvons utiliser la méthode statique de la classe java.nio.file.Paths get()Cette méthode convertit une chaîne de chemin, ou une séquence de chaînes qui, une fois jointes, forment une chaîne de chemin, en une instance de Path. Cette méthode lève également une exception InvalidPathException à l'exécution si les arguments transmis contiennent des caractères non autorisés.
Comme mentionné ci-dessus, le chemin absolu est récupéré en passant l'élément racine et la liste complète des répertoires requise pour localiser le fichier.Tandis que le chemin relatif pourrait être récupéré en combinant le chemin de base avec le chemin relatif.La récupération des deux chemins serait illustrée dans l'exemple suivant
Exemple
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);
}
}
Jusqu'à présent, nous savons ce qu'est l'interface de chemin, pourquoi avons-nous besoin de cela et comment pourrions-nous y accéder. Maintenant, nous saurions quelles sont les méthodes importantes que l'interface de chemin nous fournit.
Méthodes importantes de l'interface de chemin
getFileName() - Renvoie le système de fichiers qui a créé cet objet.
getName() - Renvoie un élément de nom de ce chemin en tant qu'objet Path.
getNameCount() - Renvoie le nombre d'éléments de nom dans le chemin.
subpath() - Renvoie un chemin relatif qui est une sous-séquence des éléments de nom de ce chemin.
getParent() - Renvoie le chemin du parent, ou null si ce chemin n'a pas de parent.
getRoot() - Renvoie le composant racine de ce chemin en tant qu'objet Path, ou null si ce chemin n'a pas de composant racine.
toAbsolutePath() - Renvoie un objet Path représentant le chemin absolu de ce chemin.
toRealPath() - Renvoie le chemin réel d'un fichier existant.
toFile() - Renvoie un objet File représentant ce chemin.
normalize() - Renvoie un chemin qui est ce chemin avec les éléments de nom redondants éliminés.
compareTo(Path other) - Compare deux chemins abstraits lexicographiquement.Cette méthode renvoie zéro si l'argument est égal à ce chemin, une valeur inférieure à zéro si ce chemin est lexicographiquement inférieur à l'argument, ou une valeur supérieure à zéro si ce chemin est lexicographiquement supérieur à l'argument .
endsWith(Path other) - Teste si ce chemin se termine par le chemin donné.Si le chemin donné a N éléments, et aucun composant racine, et que ce chemin a N éléments ou plus, alors ce chemin se termine par le chemin donné si les N derniers éléments de chaque chemin, à partir de l'élément le plus éloigné de la racine, sont égaux.
endsWith(String other) - Teste si ce chemin se termine par un chemin, construit en convertissant la chaîne de chemin donnée, exactement de la manière spécifiée par la méthode endsWith (Path).
Exemple
L'exemple suivant illustre les différentes méthodes de l'interface Path qui sont mentionnées ci-dessus -
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);
}
}
Le package Java NIO fournit une autre API utilitaire nommée Files qui est essentiellement utilisée pour manipuler des fichiers et des répertoires à l'aide de ses méthodes statiques qui fonctionnent principalement sur l'objet Path.
Comme mentionné dans le didacticiel Path, l'interface Path est introduite dans le package Java NIO au cours de la version Java 7 du package de fichiers. Ce didacticiel concerne donc le même package File.
Cette classe se compose exclusivement de méthodes statiques qui opèrent sur des fichiers, des répertoires ou d'autres types de fichiers. Dans la plupart des cas, les méthodes définies ici délégueront au fournisseur de système de fichiers associé le soin d'effectuer les opérations sur les fichiers.
Il existe de nombreuses méthodes définies dans la classe Files qui peuvent également être lues à partir de documents Java.Dans ce didacticiel, nous avons essayé de couvrir certaines des méthodes importantes parmi toutes les méthodes de la classe Java NIO Files.
Méthodes importantes de la classe Files.
Voici les méthodes importantes définies dans la classe Java NIO Files.
createFile(Path filePath, FileAttribute attrs) - La classe Files fournit cette méthode pour créer un fichier à l'aide du chemin spécifié.
Exemple
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();
}
}
}
Production
Created a file at : D:\data\file.txt
copy(InputStream in, Path target, CopyOption… options) - Cette méthode est utilisée pour copier tous les octets du flux d'entrée spécifié vers le fichier cible spécifié et renvoie le nombre d'octets lus ou écrits sous forme de valeur longue.LinkOption pour ce paramètre avec les valeurs suivantes -
COPY_ATTRIBUTES - copier les attributs dans le nouveau fichier, par exemple l'attribut de dernière modification.
REPLACE_EXISTING - remplacer un fichier existant s'il existe.
NOFOLLOW_LINKS - Si un fichier est un lien symbolique, le lien lui-même, et non la cible du lien, est copié.
Exemple
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);
}
}
}
Production
To be or not to be?
createDirectories(Path dir, FileAttribute<?>...attrs) - Cette méthode est utilisée pour créer des répertoires en utilisant un chemin donné en créant tous les répertoires parents inexistants.
delete(Path path) - Cette méthode est utilisée pour supprimer le fichier du chemin spécifié.Elle lance NoSuchFileException si le fichier n'existe pas au chemin spécifié ou si le fichier est un répertoire et qu'il ne peut pas être vide et ne peut pas être supprimé.
exists(Path path) - Cette méthode est utilisée pour vérifier si le fichier existe au chemin spécifié et si le fichier existe, il retournera vrai ou bien il retournera faux.
readAllBytes(Path path) - Cette méthode est utilisée pour lire tous les octets du fichier au chemin donné et retourne le tableau d'octets contenant les octets lus dans le fichier.
Exemple
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);
}
}
}
Production
Welcome to file.
size(Path path) - Cette méthode est utilisée pour obtenir la taille du fichier au chemin spécifié en octets.
write(Path path, byte[] bytes, OpenOption… options) - Cette méthode est utilisée pour écrire des octets dans un fichier au chemin spécifié.
Exemple
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);
}
}
}
Production
To be or not to be?
Comme nous savons que Java NIO prend en charge la concurrence et le multi-threading, ce qui nous permet de traiter simultanément différents canaux en même temps.Ainsi, l'API qui en est responsable dans le package Java NIO est AsynchronousFileChannel qui est défini sous le package de canaux NIO. pour AsynchronousFileChannel est java.nio.channels.AsynchronousFileChannel.
AsynchronousFileChannel est similaire à celui du FileChannel du NIO, sauf que ce canal permet aux opérations sur les fichiers de s'exécuter de manière asynchrone, contrairement à une opération d'E / S synchrone dans laquelle un thread entre dans une action et attend que la requête soit terminée. par plusieurs threads simultanés.
En asynchrone, la demande est transmise par thread au noyau du système d'exploitation pour le faire pendant que le thread continue de traiter un autre travail.Une fois le travail du noyau terminé, il signale le thread, puis le thread a reconnu le signal et interrompt le travail en cours et traite le Travail d'E / S selon les besoins.
Pour obtenir la concurrence, ce canal propose deux approches, dont une en renvoyant un java.util.concurrent.Future object et l'autre passe à l'opération un objet de type java.nio.channels.CompletionHandler.
Nous comprendrons les deux approches à l'aide d'exemples une par une.
Future Object - Dans ce cas, une instance de Future Interface est renvoyée depuis le canal. get() qui retourne l'état de l'opération gérée de manière asynchrone sur la base de laquelle une exécution ultérieure d'une autre tâche pourrait être décidée.Nous pouvons également vérifier si la tâche est terminée ou non en appelant son isDone méthode.
Exemple
L'exemple suivant montre comment utiliser l'objet Future et effectuer des tâches de manière asynchrone.
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();
}
}
Production
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 -
Cette approche est assez simple, car nous utilisons l'interface CompletionHandler et remplace ses deux méthodes, l'une est completed() méthode qui est appelée lorsque l'opération d'E / S se termine avec succès et que l'autre est failed() qui est appelée si les opérations d'E / S échouent. Dans ce cas, un gestionnaire est créé pour consommer le résultat d'une opération d'E / S asynchrone, car une fois qu'une tâche est terminée, seul le gestionnaire a des fonctions qui sont exécutées.
Exemple
L'exemple suivant montre comment utiliser CompletionHandler pour effectuer des tâches de manière asynchrone.
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();
}
}
Production
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.
En Java, pour chaque caractère, il existe des unités de code Unicode bien définies qui sont gérées en interne par JVM. Ainsi, le package Java NIO définit une classe abstraite nommée Charset qui est principalement utilisée pour l'encodage et le décodage de charset et UNICODE.
Jeux de caractères standard
Les jeux de caractères pris en charge en java sont indiqués ci-dessous.
US-ASCII - Caractères ASCII à sept bits.
ISO-8859-1 - Alphabet latin ISO.
UTF-8 - Il s'agit du format de transformation UCS 8 bits.
UTF-16BE - Il s'agit d'un format de transformation UCS 16 bits avec un ordre d'octets big endian.
UTF-16LE - Il s'agit d'une transformation UCS 16 bits avec un ordre d'octet peu fin.
UTF-16 - Format de transformation UCS 16 bits.
Méthodes importantes de la classe Charset
forName() - Cette méthode crée un objet charset pour le nom charset donné. Le nom peut être canonique ou un alias.
displayName() - Cette méthode renvoie le nom canonique du jeu de caractères donné.
canEncode() - Cette méthode vérifie si le jeu de caractères donné prend en charge l'encodage ou non.
decode() - Cette méthode décode la chaîne d'un jeu de caractères donné en charbuffer d'un jeu de caractères Unicode.
encode() - Cette méthode encode le charbuffer du jeu de caractères unicode dans le tampon d'octets du jeu de caractères donné.
Exemple
L'exemple suivant illustre des méthodes importantes de la classe Charset.
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();
}
}
Production
US-ASCII
Demo text for conversion.
Comme nous savons que Java NIO prend en charge la concurrence et le multi-threading, ce qui lui permet de gérer plusieurs threads fonctionnant sur plusieurs fichiers en même temps, mais dans certains cas, nous exigeons que notre fichier ne soit pas partagé par aucun thread et ne devienne pas accessible.
Pour une telle exigence, NIO fournit à nouveau une API connue sous le nom de FileLock qui est utilisée pour fournir un verrou sur tout le fichier ou sur une partie de fichier, de sorte que le fichier ou sa partie ne soit pas partagé ou accessible.
afin de fournir ou d'appliquer un tel verrou, nous devons utiliser FileChannel ou AsynchronousFileChannel, qui fournit deux méthodes lock() et tryLock()à cet effet, la serrure fournie peut être de deux types -
Exclusive Lock - Un verrou exclusif empêche les autres programmes d'acquérir un verrou superposé de l'un ou l'autre type.
Shared Lock - Un verrou partagé empêche d'autres programmes exécutés simultanément d'acquérir un verrou exclusif qui se chevauchent, mais leur permet d'acquérir des verrous partagés qui se chevauchent.
Méthodes utilisées pour obtenir le verrouillage du fichier -
lock() - Cette méthode de FileChannel ou AsynchronousFileChannel acquiert un verrou exclusif sur un fichier associé au canal donné. Le type de retour de cette méthode est FileLock qui est en outre utilisé pour surveiller le verrou obtenu.
lock(long position, long size, boolean shared) - Cette méthode est à nouveau la méthode surchargée de la méthode de verrouillage et est utilisée pour verrouiller une partie particulière d'un fichier.
tryLock() - Cette méthode renvoie un FileLock ou un null si le verrou n'a pas pu être acquis et qu'elle tente d'acquérir un verrou explicitement exclusif sur le fichier de ce canal.
tryLock(long position, long size, boolean shared) - Cette méthode tente d'acquérir un verrou sur la région donnée du fichier de ce canal qui peut être de type exclusif ou partagé.
Méthodes de la classe FileLock
acquiredBy() - Cette méthode renvoie le canal sur lequel le verrouillage de fichier a été acquis.
position() - Cette méthode renvoie la position dans le fichier du premier octet de la région verrouillée.Une région verrouillée n'a pas besoin d'être contenue dans, ni même de chevaucher, le fichier sous-jacent réel, de sorte que la valeur renvoyée par cette méthode peut dépasser la taille actuelle du fichier.
size() - Cette méthode renvoie la taille de la région verrouillée en octets.Une région verrouillée n'a pas besoin d'être contenue dans le fichier sous-jacent, ni même de chevaucher, de sorte que la valeur renvoyée par cette méthode peut dépasser la taille actuelle du fichier.
isShared() - Cette méthode est utilisée pour déterminer si le verrouillage est partagé ou non.
overlaps(long position,long size) - Cette méthode indique si ce verrou chevauche ou non la plage de verrouillage donnée.
isValid() - Cette méthode indique si le verrou obtenu est valide ou non. Un objet de verrouillage reste valide jusqu'à ce qu'il soit libéré ou que le canal de fichier associé soit fermé, selon la première éventualité.
release()- Libère le verrou obtenu.Si l'objet verrou est valide, l'appel de cette méthode libère le verrou et rend l'objet invalide. Si cet objet de verrouillage n'est pas valide, l'appel de cette méthode n'a aucun effet.
close()- Cette méthode appelle la méthode release (). Il a été ajouté à la classe pour pouvoir être utilisé conjointement avec la construction de bloc de gestion automatique des ressources.
Exemple pour démontrer le verrouillage de fichier.
L'exemple suivant crée un verrou sur un fichier et y écrit du contenu
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();
}
}
Production
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.