Maison > Java > javaDidacticiel > le corps du texte

Explication détaillée du code et du texte du tampon Java NIO

黄舟
Libérer: 2017-03-31 11:09:12
original
1683 Les gens l'ont consulté

Un objet Buffer est un conteneur pour une quantité fixe de données. Un canal est l'entrée par laquelle les transferts d'E/S s'effectuent, et un tampon est la source ou la destination de ces transferts de données.

Bases du tampon

Tous les tampons ont quatre propriétés qui fournissent des informations sur les éléments de données qu'ils contiennent.

  • capacité (capacité) : La valeur maximale des données que le tampon peut contenir. Elle ne peut pas être modifiée une fois le tampon créé.

  • limite (limite supérieure) : Le premier élément du tampon qui ne peut pas être lu ou écrit. Alternativement, le nombre d'éléments existants dans le tampon.

  • position(position) : Le index du prochain élément à lire ou à écrire. L’appel de la fonction get ou put sera mis à jour.

  • marque : un emplacement mémo. Appelez mark() pour définir mark=postion. Appelez reset() pour définir position= mark. La balise n'est pas définie jusqu'à ce qu'elle soit définie.

Il existe toujours la relation suivante entre ces quatre propriétés :

0 <= mark <= position <= limit <= capacity
Copier après la connexion

L'image ci-dessous est un ByteBuffer nouvellement créé :

La position est définie sur 0, et la capacité et la limite supérieure sont définies sur 10, de manière à transmettre le dernier octet que le tampon peut contenir. La balise est initialement indéfinie. La capacité est fixe, mais les trois autres propriétés peuvent être modifiées lors de l'utilisation du tampon.

Ce qui suit est la signature de la méthode de Buffer :

public abstract class Buffer {

    public final int capacity() {
    }

    public final int position() {
    }

    public final Buffer position(int newPosition) {
    }

    public final int limit() {
    }

    public final Buffer limit(int newLimit) {
    }

    public final Buffer mark() {
    }

    public final Buffer reset() {
    }

    public final Buffer clear() {
    }

    public final Buffer flip() {
    }

    public final Buffer rewind() {
    }

    public final int remaining() {
    }

    public final boolean hasRemaining() {
    }

    public abstract boolean isReadOnly();

    public abstract boolean hasArray();

    public abstract Object array();

    public abstract int arrayOffset();

    public abstract boolean isDirect();
}
Copier après la connexion

L'API de Buffer répertoriée ci-dessus n'inclut pas les fonctions get() ou put(). Chaque classe Buffer a ces deux fonctions, mais les types de paramètres qu'elles prennent et le type de données qu'elles renvoient sont uniques à chaque sous-classe, elles ne peuvent donc pas être déclarées de manière abstraite dans la classe Buffer de niveau supérieur.

Ce qui suit est la déclaration de ByteBuffer :

public abstract class ByteBuffer extends Buffer implements Comparable
{
    // This is a partial API listing
    public abstract byte get( );
    public abstract byte get (int index);
    public abstract ByteBuffer put (byte b);
    public abstract ByteBuffer put (int index, byte b);
}
Copier après la connexion

Un exemple regarde le stockage de ByteBuffer :

buffer.put((byte)&#39;H&#39;).put((byte)&#39;e&#39;).put((byte)&#39;l&#39;).put((byte)&#39;l&#39;).put((byte)&#39;o&#39;);
Copier après la connexion

Si vous effectuez l'opération suivante :

buffer.put(0,(byte)&#39;M&#39;).put((byte)&#39;w&#39;);
Copier après la connexion

Lorsque le tampon est plein et pour lire le contenu, nous devons retourner le tampon et appeler la méthode flip. Voici la méthode flip dans ByteBuffer :

public final Buffer flip() {
        limit = position;
        position = 0;
        mark = -1;
        return this;
    }
Copier après la connexion

La fonction rewind() est similaire à flip(), mais n'affecte pas la propriété de limite supérieure. Cela remet simplement la valeur de position à 0. Vous pouvez utiliser rewind() pour relire les données du tampon qui a été inversé. La méthode

hasRemaining() retournera si la limite supérieure du tampon est actuellement atteinte. La méthode

remaining() renvoie la distance jusqu'à la limite supérieure.

La marque du tampon n'est pas définie avant l'appel de la fonction mark(), et lorsqu'elle est appelée, la marque est définie sur la valeur de la position actuelle. La fonction

reset() définit la position sur la valeur actuelle du marqueur. Si la valeur de la marque n'est pas définie, l'appel de reset() entraînera une exception InvalidMarkException.

rewind( ), clear( ) et flip( ) rejettent toujours le drapeau, c'est-à-dire mis à -1.

Les conditions nécessaires et suffisantes pour que deux buffers soient considérés comme égaux sont :

  • Les deux objets sont du même type. Les tampons contenant différents types de données sont loin d’être égaux et les tampons ne sont jamais égaux aux objets non tampons.

  • Les deux objets ont le même nombre d'éléments restants. Les capacités des tampons ne doivent pas nécessairement être les mêmes, et les indices des données restantes dans les tampons ne doivent pas nécessairement être les mêmes. Mais le nombre d'éléments restants dans chaque tampon (de la position à la limite supérieure) doit être le même.

  • La séquence des éléments de données restants qui doivent être renvoyés par la fonction Get() doit être cohérente dans chaque tampon.

Créer un tampon

//分配一个容量为 100 个 char 变量的 Charbuffer
CharBuffer charBuffer = CharBuffer.allocate (100);

char [] myArray = new char [100];
CharBuffer charbuffer = CharBuffer.wrap (myArray);
//这段代码构造了一个新的缓冲区对象,但数据元素会存在于数组中。
这意味着通过调用 put()函数造成的对缓冲区的改动会直接影响这个数组,而且对这个数组的任何改动也会对这 个缓冲区对象可见。

CharBuffer.wrap(array, offset, length);可以指定 position 和 length
Copier après la connexion

via allocate() ou wrap() Buffers créés par les fonctions sont généralement indirects et les tampons indirects utilisent des tableaux de sauvegarde. hasArray() Renvoie si ce tampon a un tableau de sauvegarde accessible.

Tampon de copie

Quelques API de tampon de copie :

public abstract class CharBuffer extends Buffer implements CharSequence, Comparable {
	// This is a partial API listing
	public abstract CharBuffer duplicate( );
	public abstract CharBuffer asReadOnlyBuffer( );
	public abstract CharBuffer slice( );
}
Copier après la connexion

duplicate() 函数创建了一个与原始缓冲区相似的新缓冲区。两个缓冲区共享数据元素,拥有同样的容量,但每个缓冲区拥有各自的位置,上界和标记属性。对一个缓冲区内的数据元素所做的改变会反映在另外一个缓冲区上。如果原始的缓冲区为只读,或者为直接缓冲区,新的缓冲区将继承这些属性。

如下示例:

public static void main(String[] args) {
		CharBuffer buffer = CharBuffer.allocate(8);
		buffer.position(3).limit(6).mark().position(5);
		CharBuffer dupeBuffer = buffer.duplicate();
		System.out.println(dupeBuffer.position());
		System.out.println(dupeBuffer.limit());
		dupeBuffer.clear();
		System.out.println(dupeBuffer.position());
		System.out.println(dupeBuffer.limit());
	}

//out
5
6
0
8
Copier après la connexion

asReadOnlyBuffer() 函数来生成一个只读的缓冲区图。

代码说明如下:

public static void main(String[] args) {
		CharBuffer buffer = CharBuffer.allocate(8);
		CharBuffer dupeBuffer = buffer.asReadOnlyBuffer();
		System.out.println(dupeBuffer.isReadOnly());
		dupeBuffer.put(&#39;S&#39;);//只读buffer调用抛出异常
	}

//out
true
Exception in thread "main" java.nio.ReadOnlyBufferException
	at java.nio.HeapCharBufferR.put(HeapCharBufferR.java:172)
	at nio.test.TestMain.main(TestMain.java:10)
Copier après la connexion

slice() 创建一个从原始缓冲区的当前位置开始的新缓冲 区,并且其容量是原始缓冲区的剩余元素数量(limit-position)。这个新缓冲区与原始 缓冲区共享一段数据元素子序列。分出来的缓冲区也会继承只读和直接属性。

public static void main(String[] args) {
		CharBuffer buffer = CharBuffer.allocate(8);
		buffer.position(3).limit(5);
		CharBuffer sliceBuffer = buffer.slice();
	}
Copier après la connexion

字节缓冲区

在 java.nio 中,字节顺序由 ByteOrder 类封装。

ByteOrder.nativeOrder() 方法返回 JVM 运行的硬件平台字节顺序。

直接缓冲区

只有字节缓冲区有资格参与 I/O 操作。

I/O 操作的目标内存区域必须是连续的字节序列。

直接缓冲区被用于与通道和固有 I/O 例程交互。

直接字节缓冲区通常是 I/O 操作最好的选择。直接字节缓冲区支持 JVM 可用的最高效 I/O 机制。非直接字节缓冲区可以被传递给通道,但是这样可能导致性能耗。通常非直接缓冲不可能成为一个本地 I/O 操作的目标。如果向一个通道中传递一个非直接 ByteBuffer 对象用于写入会每次隐含调用下面的操作:

  1. 创建一个临时的直接 ByteBuffer 对象。

  2. 将非直接缓冲区的内容复制到直接临时缓冲中。

  3. 使用直接临时缓冲区执行低层次 I/O 操作。

  4. 直接临时缓冲区对象离开作用域,并最终成为被回的无用数据。

直接缓冲区时 I/O 的最佳选择,但可能比创建非直接缓冲区要花费更高的成本。直接缓冲区使用的内存是通过调用本地操作系统方面的代码分配的, 过了标准 JVM 。

ByteBuffer.allocateDirect() 创建直接缓冲区。isDirect() 返回是否直接缓冲区。

视图缓冲区

视图缓冲区通过已存在的缓冲区对象实例的工方法来创建。这种图对象维护它自己的属性,容量,位置,上界和标记,但是和原来的缓冲区共享数据元素。

ByteBuffer 类允许创建图来将 byte 型缓冲区字节数据映射为其它的原始数据类型。

public abstract CharBuffer asCharBuffer( );
public abstract ShortBuffer asShortBuffer( );
public abstract IntBuffer asIntBuffer( );
public abstract LongBuffer asLongBuffer( );
public abstract FloatBuffer asFloatBuffer( );
public abstract DoubleBuffer asDoubleBuffer( );
Copier après la connexion

看如下一个例子的示意图:

ByteBuffer byteBuffer = ByteBuffer.allocate (7).order (ByteOrder.BIG_ENDIAN);
CharBuffer charBuffer = byteBuffer.asCharBuffer( );
Copier après la connexion

public class BufferCharView {
       public static void main (String [] argv)  throws Exception  {
          ByteBuffer byteBuffer = ByteBuffer.allocate (7).order (ByteOrder.BIG_ENDIAN);
          CharBuffer charBuffer = byteBuffer.asCharBuffer( );
          // Load the ByteBuffer with some bytes
          byteBuffer.put (0, (byte)0);
          byteBuffer.put (1, (byte)&#39;H&#39;);
          byteBuffer.put (2, (byte)0);
          byteBuffer.put (3, (byte)&#39;i&#39;);
          byteBuffer.put (4, (byte)0);
          byteBuffer.put (5, (byte)&#39;!&#39;);
          byteBuffer.put (6, (byte)0);
          println (byteBuffer);
          println (charBuffer);
       }
       // Print info about a buffer
       private static void println (Buffer buffer)  {
		  System.out.println ("pos=" + buffer.position() + ", limit=" +
          	buffer.limit() + ", capacity=" + buffer.capacity() + ": &#39;" + buffer.toString( ) + "&#39;");
	}
}

//运行 BufferCharView 程序的输出是:
//pos=0, limit=7, capacity=7: &#39;java.nio.HeapByteBuffer[pos=0 lim=7 cap=7]&#39;
//pos=0, limit=3, capacity=3: &#39;Hi!
Copier après la connexion

数据元素视图

ByteBuffer 类为每一种原始数据类型 供了存取的和转化的方法:

public abstract class ByteBuffer extends Buffer implements Comparable {
	public abstract char getChar();

	public abstract char getChar(int index);

	public abstract short getShort();

	public abstract short getShort(int index);

	public abstract int getInt();

	public abstract int getInt(int index);

	public abstract long getLong();

	public abstract long getLong(int index);

	public abstract float getFloat();

	public abstract float getFloat(int index);

	public abstract double getDouble();

	public abstract double getDouble(int index);

	public abstract ByteBuffer putChar(char value);

	public abstract ByteBuffer putChar(int index, char value);

	public abstract ByteBuffer putShort(short value);

	public abstract ByteBuffer putShort(int index, short value);

	public abstract ByteBuffer putInt(int value);

	public abstract ByteBuffer putInt(int index, int value);

	public abstract ByteBuffer putLong(long value);

	public abstract ByteBuffer putLong(int index, long value);

	public abstract ByteBuffer putFloat(float value);

	public abstract ByteBuffer putFloat(int index, float value);

	public abstract ByteBuffer putDouble(double value);

	public abstract ByteBuffer putDouble(int index, double value);
}
Copier après la connexion

假如一个 bytebuffer 处于如下状态:

那么 int value = buffer.getInt();

实际的返回值取决于缓冲区的当前的比特排序(byte-order)设置。更具体的写法是:

int value = buffer.order (ByteOrder.BIG_ENDIAN).getInt( );
Copier après la connexion

这将会返回值 0x3BC5315E,同时:

int value = buffer.order (ByteOrder.LITTLE_ENDIAN).getInt( );
Copier après la connexion

返回值 0x5E31C53B

如果您试图获取的原始类型需要比缓冲区中存在的字节数更多的字节,会抛出 BufferUnderflowException。

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:php.cn
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