Maison  >  Article  >  Java  >  Utilisation du tampon en JAVA

Utilisation du tampon en JAVA

怪我咯
怪我咯original
2017-06-25 10:14:494887parcourir

Remarque : réimprimé de Concurrent Programming Network, tutoriels de la série Java nio

1 Buffer

Le tampon dans Java NIO est utilisé pour interagir avec les canaux NIO. Comme vous le savez, les données sont lues du canal dans le tampon et écrites du tampon dans le canal.

Un tampon est essentiellement un bloc de mémoire dans lequel des données peuvent être écrites et à partir duquel les données peuvent ensuite être lues. Cette mémoire est conditionnée sous forme d'objet NIO Buffer et fournit un ensemble de méthodes pour accéder facilement à cette mémoire.

1. L'utilisation de base de Buffer

L'utilisation de Buffer pour lire et écrire des données suit généralement les quatre étapes suivantes :

  1. Écrire des données dans Buffer

  2. Appelez la méthode flip()

  3. pour lire les données du Buffer : comme la lecture directe ou la lecture dans le canal

  4. Appelez la méthode clear() ou la méthode compact()

Lors de l'écriture de données dans le tampon, le tampon enregistrera la quantité de données écrites. Une fois que vous souhaitez lire des données, vous devez faire passer le Buffer du mode écriture au mode lecture via la méthode flip(). En mode lecture, toutes les données précédemment écrites dans le tampon peuvent être lues.

Une fois toutes les données lues, le tampon doit être vidé pour pouvoir y être réécrit. Il existe deux manières de vider le tampon : en appelant la méthode clear() ou compact(). La méthode clear() efface tout le tampon. La méthode compact() effacera uniquement les données lues. Toutes les données non lues sont déplacées au début du tampon et les données nouvellement écrites sont placées après les données non lues dans le tampon.

2. Capacité, position et limite du tampon

Un tampon est essentiellement un morceau de mémoire dans lequel des données peuvent être écrites et à partir desquelles des données peuvent être lues. Cette mémoire est conditionnée sous forme d'objet NIO Buffer et fournit un ensemble de méthodes pour accéder facilement à cette mémoire.

Afin de comprendre le fonctionnement de Buffer, vous devez connaître ses trois propriétés :

  • capacité

  • position

  • limite

La signification de la position et de la limite dépend du fait que le Buffer soit en mode lecture ou en mode écriture. Quel que soit le mode dans lequel se trouve le Buffer, la signification de la capacité est toujours la même.

Voici une explication sur la capacité, la position et la limite en mode lecture et écriture. L'explication détaillée se trouve derrière l'illustration.

capacité : capacité

En tant que bloc de mémoire, Buffer a une valeur de taille fixe, également appelée "capacité". Vous ne pouvez y écrire que de la capacité en octets. , long, char et autres types. Une fois le tampon plein, il doit être vidé (en lisant ou en effaçant des données) avant de pouvoir continuer l'écriture des données.

position : position actuelle

Lorsque vous écrivez des données dans le tampon, la position représente la position actuelle. La valeur de position initiale est 0. Lorsqu'un octet, une donnée longue, etc. est écrit dans le tampon, la position avance jusqu'à l'unité tampon suivante où les données peuvent être insérées. La position maximale peut être la capacité – 1.

Lors de la lecture des données, elles sont également lues à partir d'une position spécifique. Lorsque le tampon passe du mode écriture au mode lecture, la position sera réinitialisée à 0. Lorsque les données sont lues à partir de la position du tampon, la position avance jusqu'à la position lisible suivante.

limite : position maximale inscriptible/lisible

En mode écriture, la limite du Buffer indique la quantité maximale de données que vous pouvez écrire dans le Buffer. En mode écriture, la limite est égale à la capacité du Buffer.

Lorsque vous passez le tampon en mode lecture, la limite indique la quantité maximale de données que vous pouvez lire. Par conséquent, lors du passage du tampon en mode lecture, la limite sera définie sur la valeur de position en mode écriture. En d'autres termes, vous pouvez lire toutes les données écrites auparavant (la limite est fixée au nombre de données écrites, cette valeur est la position en mode écriture)

3. Type de tampon

Java NIO a les types de tampon suivants

  • ByteBuffer

  • MappedByteBuffer

  • CharBuffer

  • DoubleBuffer

  • FloatBuffer

  • IntBuffer

  • LongBuffer

  • ShortBuffer

Comme vous pouvez le voir, ces types de Buffer représentent différents types de données. En d’autres termes, les octets du tampon peuvent être manipulés via les types char, short, int, long, float ou double.

MappedByteBuffer est un peu spécial, et sera abordé dans son chapitre dédié.

4. Allocation de Buffer

Pour obtenir un objet Buffer, vous devez d'abord l'allouer. Chaque classe Buffer a une méthode d'allocation. Vous trouverez ci-dessous un exemple d'allocation d'un ByteBuffer d'une capacité de 50 octets.

ByteBuffer buf = ByteBuffer.allocate(50);

5. Écrire des données dans Buffer

Il existe deux façons d'écrire des données dans Buffer :

  • Écrivez du canal au tampon.

  • est écrit dans le Buffer via la méthode put() de Buffer.

  • Lors de l'initialisation du Buffer, placez le tableau d'octets dans le Buffer

public void test1() throws FileNotFoundException {//初始化容量ByteBuffer buf1 = ByteBuffer.allocate(48);//通过数组初始化,并将数组中的值放入缓冲区byte[] bytes = "123".getBytes();
        ByteBuffer buf2 = ByteBuffer.wrap(bytes);//将通道中的读到缓冲区int bytesRead = channel.read(bf);//通过put方法写入缓冲区,put有很多重载        buf1.put(bytes);
    }

put方法有很多版本,允许你以不同的方式把数据写入到Buffer中。例如, 写到一个指定的位置,或者把一个字节数组写入到Buffer。 

flip()方法

flip方法将Buffer从写模式切换到读模式。调用flip()方法会将position设回0,并将limit设置成之前position的值。

换句话说,position现在用于标记读的位置,limit表示之前写进了多少个byte、char等 —— 现在能读取多少个byte、char等。

六、从Buffer中读取数据

从Buffer中读取数据有两种方式:

  1. 从Buffer读取数据到Channel。

  2. 使用get()方法从Buffer中读取数据。

        //将缓冲区的数据写入通道        channel.write(buf1);//通过get方法获取缓冲区中数据 get有很多重载buf1.get();

 

 

La méthode get a de nombreuses versions, vous permettant de lire les données du Buffer de différentes manières. Par exemple, lisez à partir d'une position spécifiée ou lisez les données d'un tampon dans un tableau d'octets.

7. Méthode rewind() : réinitialiser la position

Buffer.rewind() remet la position à 0, afin que vous puissiez relire toutes les données du Buffer. La limite reste inchangée et indique toujours combien d'éléments (octet, caractère, etc.) peuvent être lus à partir du Buffer.

8. Méthodes Clear() et compact()

Une fois les données du Buffer lues, le Buffer doit être prêt à être réécrit. Cela peut être fait via les méthodes clear() ou compact().

Si la méthode clear() est appelée, la position sera remise à 0 et la limite sera fixée à la valeur de capacité. En d’autres termes, le Buffer est vidé. Les données du Buffer ne sont pas effacées, mais ces marques nous indiquent par où commencer à écrire les données dans le Buffer.

S'il y a des données non lues dans le Buffer et que la méthode clear() est appelée, les données seront "oubliées", ce qui signifie qu'il n'y aura plus de marqueurs pour vous indiquer quelles données ont été lues et ce qui n'est pas le cas.

S'il y a encore des données non lues dans le tampon et que les données sont nécessaires plus tard, mais que vous souhaitez d'abord écrire des données, utilisez la méthode compact().

La méthode compact() copie toutes les données non lues au début du Buffer. Définissez ensuite la position juste derrière le dernier élément non lu. L'attribut limit est toujours défini sur capacité comme la méthode clear(). Le tampon est maintenant prêt à écrire des données, mais les données non lues ne seront pas écrasées.

9. Méthodes Mark() et reset() : marquer la position et retourner la position

En appelant la méthode Buffer.mark(), vous pouvez marquer une position spécifique dans le Buffer. Vous pourrez ultérieurement restaurer cette position en appelant la méthode Buffer.reset(). Par exemple :

10. Méthodes equals() et compareTo()

Vous pouvez utiliser les méthodes equals() et compareTo() pour comparer deux Buffers.

equals()

Lorsque les conditions suivantes sont remplies, cela signifie que les deux Buffers sont égaux :

  1. Avoir le même type (octet, char, int, etc.).

  2. Le nombre d'octets, de caractères, etc. restant dans le tampon est égal.

  3. Tous les octets, caractères, etc. restants dans le tampon sont les mêmes.

Comme vous pouvez le voir, égal ne compare qu'une partie du Buffer, pas tous les éléments qu'il contient. En fait, il compare uniquement les éléments restants du Buffer.

MéthodecompareTo()

La méthodecompareTo() compare les éléments restants (octet, caractère, etc.) de deux Buffers Si les conditions suivantes sont remplies, un Buffer est considéré comme "inférieur à". " l'autre Buffer :

  1. Le premier élément inégal est plus petit que l'élément correspondant dans l'autre Buffer.

  2. Tous les éléments sont égaux, mais le premier Buffer est épuisé avant l'autre (le premier Buffer a moins d'éléments que l'autre).

(Traduction : les éléments restants sont les éléments de la position à la limite)

2. Les soi-disant Scatter et Gather sont des canaux correspondant à plusieurs caches : lecture d'un canal dans plusieurs caches ; écriture de plusieurs caches sur un seul canal

Java NIO commence à prendre en charge scatter/gather, scatter/gather Utilisé pour décrire l'opération. de lire ou d'écrire sur Channel (Note du traducteur : Channel est souvent traduit par canal en chinois).

La lecture dispersée à partir du canal signifie l'écriture des données lues dans plusieurs tampons pendant l'opération de lecture. Par conséquent, le canal "disperse" les données lues du canal dans plusieurs tampons

L'écriture sur le canal signifie écrire des données de plusieurs tampons dans le même tampon lors d'une opération d'écriture sur le canal A, par conséquent, le canal "rassemble" les données. données dans plusieurs tampons et les envoie au canal.

La dispersion/collecte est souvent utilisée dans les situations où les données transmises doivent être traitées séparément. Par exemple, lors de la transmission d'un message composé d'un en-tête de message et d'un corps de message, vous pouvez disperser le corps du message et l'en-tête du message. dans différents tampons, afin que vous puissiez facilement gérer l'en-tête et le corps du message.


Lectures dispersées

Les lectures dispersées signifient que les données sont lues à partir d'un canal vers plusieurs tampons. Comme décrit ci-dessous :

Java NIO : lecture disperséeJava NIO: Scattering Read

注意buffer首先被插入到数组,然后再将数组作为channel.read() 的输入参数。read()方法按照buffer在数组中的顺序将从channel中读取的数据写入到buffer,当一个buffer被写满后,channel紧接着向另一个buffer中写。

Scattering Reads在移动下一个buffer前,必须填满当前的buffer,这也意味着它不适用于动态消息(译者注:消息大小不固定)。换句话说,如果存在消息头和消息体,消息头必须完成填充(例如 128byte),Scattering Reads才能正常工作。

Gathering Writes

Gathering Writes是指数据从多个buffer写入到同一个channel。如下图描述:

Java NIO: Gathering Write

Java NIO: Gathering Write

 

buffers数组是write()方法的入参,write()方法会按照buffer在数组中的顺序,将数据写入到channel,注意只有position和limit之间的数据才会被写入。因此,如果一个buffer的容量为128byte,但是仅仅包含58byte的数据,那么这58byte的数据将被写入到channel中。因此与Scattering Reads相反,Gathering Writes能较好的处理动态消息

    ByteBuffer header = ByteBuffer.allocate(128);
    ByteBuffer body   = ByteBuffer.allocate(1024);
    ByteBuffer[] bufferArray = { header, body };
    channel.read(bufferArray);  //传入Buffer数组即可//方便展示、直接写,写之前要反转bufferchannel.write(bufferArray);

 

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!

Déclaration:
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