Maison > Java > Javacommencer > Une introduction détaillée à Java NIO

Une introduction détaillée à Java NIO

王林
Libérer: 2020-10-21 16:35:21
avant
1837 Les gens l'ont consulté

Une introduction détaillée à Java NIO

Java NIO doit principalement comprendre les trois concepts fondamentaux de tampons, de canaux et de sélecteurs en complément des E/S Java pour améliorer l'efficacité de la transmission de données de gros volumes.

(Tutoriel recommandé : cours Java)

Il est préférable d'avoir des connaissances de base en programmation réseau avant d'apprendre NIO

Flux d'E/S Java

Programmation réseau Java

Java NIO : Buffer

Channel (Channel), comme l'un des trois concepts fondamentaux de NIO (tampon, canal, sélecteur), est utilisé dans Transmettre efficacement données entre le tampon d'octets et l'entité (fichier ou socket) de l'autre côté du canal (le noyau est de transmettre des données)

Le modèle général de la programmation NIO est le suivant : remplissez les données dans la section du mot d'envoi buffer --> Envoyer au fichier homologue du canal ou au socket via le canal

Bases du canal

Le but de l'utilisation du canal est de transmettre des données avant utilisation. être ouvert et le canal doit être fermé après utilisation

Ouvrir le canal

Nous savons qu'il existe deux grandes catégories d'E/S : File IO et Stream I /O, qui correspondent à Il existe deux types de canaux : le canal de fichier (FileChannel) et le canal de socket (SocketChannel, ServerSocketChannel, DatagramChannel)

Pour les canaux de socket, utilisez la méthode de fabrique statique pour ouvrir

SocketChannel sc = SocketChannel.open();
ServerSocketChannel sc = ServerSocketChannel.open();
DatagramChannel sc = DatagramChannel.open();
Copier après la connexion

Pour les canaux de fichiers Il ne peut être obtenu qu'en appelant la méthode getChannel() sur un objet RandomAccessFile, FileInputStream et FileOutputStream à ByteBuffer, puis en ouvrant le canal de fichier et en plaçant les données du tampon dans le canal de fichier.

FileInputStream in = new FileInputStream("/tmp/a.txt");
FileChannel fc = in.getChannel();
Copier après la connexion

Fermez le canal

Tout comme Socket, FileInputStream et d'autres objets doivent être fermés après utilisation, le canal doit également être fermé après utilisation. Un canal ouvert représente une connexion spécifique à un service d'E/S spécifique et encapsule l'état de cette connexion. Lorsque le canal est fermé, la connexion est perdue et rien n'y est connecté.

Mode bloquant et non bloquant

Le canal dispose de deux modes de fonctionnement : bloquant et non bloquant. Le canal en mode non bloquant ne se mettra jamais en veille, et le. L'opération demandée sera terminée immédiatement, ou renverra un résultat indiquant qu'aucune opération n'a été effectuée (voir la description du canal Socket pour plus de détails). Seuls les canaux orientés flux peuvent utiliser le mode non bloquant

Canaux de fichiers

Les canaux de fichiers sont utilisés pour accéder aux fichiers en appelant getChannel sur un objet RandomAccessFile, FileInputStream, FileOutputStream ( ) méthode pour obtenir. L'appel de la méthode getChannel renvoie un objet FileChannel connecté au même fichier avec les mêmes droits d'accès que l'objet fichier.

Accès aux fichiers

Le but de l'utilisation des canaux de fichiers est de lire et d'écrire des fichiers. L'API de lecture et d'écriture du canal est la suivante :

//准备数据并放入字节缓冲区
ByteBuffer bf = ByteBuffer.allocate(1024);
bf.put("i am cool".getBytes());
bf.flip();
//打开文件通道
FileOutputStream out = new FileOutputStream("/tmp/a.txt");
FileChannel fc = out.getChannel();
//数据传输
fc.write(bf);
//关闭通道
fc.close();
Copier après la connexion
<. 🎜>Ce qui suit est un paragraphe Démo pour lire des fichiers

public abstract int read(ByteBuffer dst) throws IOException;
public abstract int write(ByteBuffer src) throws IOException;
Copier après la connexion
Il y a un problème avec la démo ci-dessus : on ne peut lire que les octets, puis laisser l'application les décoder. Pour résoudre ce problème, nous pouvons utiliser le. classe d'outils Canaux pour envelopper le canal dans la solution Reader et Writer ; bien sûr, nous pouvons également utiliser directement le mode flux Reader et Writer de Java I/O pour exploiter les caractères

Position et fichier du canal de fichier. trou

Position du canal de fichier (position) C'est la position d'un fichier ordinaire. La valeur de position détermine quelle position dans le fichier sera lue ou écrite ensuite

Lecture des données au-delà. la fin du fichier renverra -1 (fichier EOF)

L'écriture de données à une position au-delà de la fin du fichier provoquera des trous dans le fichier : par exemple, un fichier contient actuellement 10 octets, mais l'écriture de données à la position =20 à ce moment fera que la position entre 10 et 20 sera vide. Données, c'est un trou de fichier

opération forcée

L'opération forcée force le canal. pour appliquer immédiatement toutes les modifications au fichier disque (pour éviter que les modifications ne soient perdues en raison d'un temps d'arrêt du système)

//打开文件channel
RandomAccessFile f = new RandomAccessFile("/tmp/a.txt", "r");
FileChannel fc = f.getChannel();
//从channel中读取数据,直到文件尾
ByteBuffer bb = ByteBuffer.allocate(1024);
while (fc.read(bb) != -1) {
;
}
//翻转(读之前需要先进行翻转)
bb.flip();
StringBuilder builder = new StringBuilder();
//把每一个字节转为字符(ascii编码)
while (bb.hasRemaining()) {
builder.append((char) bb.get());
}
System.out.println(builder.toString());
Copier après la connexion

Mappage de fichiers mémoire

FileChannel fournit une méthode map() , qui peut établir une connexion virtuelle entre un fichier ouvert et un type spécial de carte mémoire ByteBuffer (MappedByteBuffer).

Étant donné que l'objet MappedByteBuffer renvoyé par la méthode map est un tampon direct, il est très efficace d'exploiter des fichiers via MappedByteBuffer (en particulier lors du transfert de grandes quantités de données)

Utilisation de MappedByteBuffer

Lire des fichiers via MappedByteBuffer

public abstract void force(boolean metaData) throws IOException;
Copier après la connexion

Trois modes de MappedByteBuffer

READ_ONLY

READ_WRITE

PRIVÉ

Les modes lecture seule et lecture-écriture sont faciles à comprendre. En mode PRIVÉ, l'opération d'écriture écrit un tampon temporaire et n'écrit pas réellement le fichier. (Copier en écrivant l'idée)

Canal Socket

Le canal Socket peut fonctionner en mode non bloquant et est facultatif. Ces deux points nous font ne plus penser à la programmation réseau. . Vous devez créer un thread pour chaque connexion Socket, mais utilisez un seul thread pour gérer des centaines ou des milliers de connexions Socket.

Tous les canaux Socket créeront un objet Socket d'un objet lorsqu'ils sont instanciés. Les canaux Socket ne sont pas responsables des opérations liées au protocole sont déléguées aux objets socket homologues (tels que les objets SocketChannel sont délégués à Socket. objet)

非阻塞模式

相较于传统Java Socket的阻塞模式,SocketChannel提供了非阻塞模式,以构建高性能的网络应用程序

非阻塞模式下,几乎所有的操作都是立刻返回的。比如下面的SocketChannel运行在非阻塞模式下,connect操作会立即返回,如果success为true代表连接已经建立成功了, 如果success为false, 代表连接还在建立中(tcp连接需要一些时间)。

 //打开Socket通道
 SocketChannel ch = SocketChannel.open();
 //非阻塞模式
 ch.configureBlocking(false);
 //连接服务器 
 boolean success = ch.connect(InetSocketAddress.createUnresolved("127.0.0.1", 7001));
 //轮训连接状态, 如果连接还未建立就可以做一些别的工作
 while (!ch.finishConnect()){
    //dosomething else
 }
 //连接建立, 做正事
 //do something;
Copier après la connexion

ServerSocketChannel

ServerSocketChannel与ServerSocket类似,只是可以运行在非阻塞模式下

下为一个通过ServerSocketChannel构建服务器的简单例子,主要体现了非阻塞模式,核心思想与ServerSocket类似

ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
ssc.bind(new InetSocketAddress(7001));
while (true){
  SocketChannel sc = ssc.accept();
  if(sc != null){
    handle(sc);
  }else {
    Thread.sleep(1000);
  }
}
Copier après la connexion

SocketChannel 与 DatagramChannel

SocketChannel 对应 Socket, 模拟TCP协议;DatagramChannel对应DatagramSocket, 模拟UDP协议

二者的使用与SeverSocketChannel大同小异,看API即可

工具类

文体通道那里我们提到过, 通过只能操作字节缓冲区, 编解码需要应用程序自己实现。如果我们想在通道上直接操作字符,我们就需要使用工具类Channels,工具类Channels提供了通道与流互相转换、通道转换为阅读器书写器的能力,具体API入下

//通道 --> 输入输出流
public static OutputStream newOutputStream(final WritableByteChannel ch);
public static InputStream newInputStream(final AsynchronousByteChannel ch);
//输入输出流 --> 通道
public static ReadableByteChannel newChannel(final InputStream in);
public static WritableByteChannel newChannel(final OutputStream out);
//通道  --> 阅读器书写器
public static Reader newReader(ReadableByteChannel ch, String csName);
public static Writer newWriter(WritableByteChannel ch, String csName);
Copier après la connexion

通过将通道转换为阅读器、书写器我们就可以直接在通道上操作字符。

    RandomAccessFile f = new RandomAccessFile("/tmp/a.txt", "r");
  FileChannel fc = f.getChannel();
  //通道转换为阅读器,UTF-8编码
  Reader reader = Channels.newReader(fc, "UTF-8");
  int i = 0, s = 0;
  char[] buff = new char[1024];
  while ((i = reader.read(buff, s, 1024 - s)) != -1) {
    s += i;
  }
  for (i = 0; i < s; i++) {
    System.out.print(buff[i]);
  }
Copier après la connexion

总结

通道主要分为文件通道和套接字通道。

对于文件操作:如果是大文件使用通道的文件内存映射特性(MappedByteBuffer)来有利于提升传输性能, 否则我更倾向传统的I/O流模式(字符API);对于套接字操作, 使用通道可以运行在非阻塞模式并且是可选择的,利于构建高性能网络应用程序。

相关推荐:java入门

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:juejin.im
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal