>Java >java지도 시간 >Java NIO 버퍼의 코드 및 텍스트에 대한 자세한 설명

Java NIO 버퍼의 코드 및 텍스트에 대한 자세한 설명

黄舟
黄舟원래의
2017-03-31 11:09:121692검색

버퍼 객체 는 고정된 양의 데이터를 담는 컨테이너입니다. 채널은 I/O 전송이 발생하는 항목이고 버퍼는 이러한 데이터 전송의 소스 또는 대상입니다.

버퍼 기본

모든 버퍼에는 포함된 데이터 요소에 대한 정보를 제공하는 4개의 속성이 있습니다.

  • 용량(capacity): 버퍼가 담을 수 있는 데이터의 최대값. 버퍼가 생성된 후에는 변경할 수 없습니다.

  • 제한(상한): 읽거나 쓸 수 없는 버퍼의 첫 번째 요소입니다. 또는 버퍼에 있는 기존 요소의 개수입니다.

  • 위치(위치): 읽거나 쓸 다음 요소의 색인입니다. get 또는 put 함수를 호출하면 업데이트됩니다.

  • 마크: 메모 위치. mark()를 호출하여 mark=position을 설정합니다. 위치= 표시를 설정하려면 재설정()을 호출하세요. 태그는 설정될 때까지 정의되지 않습니다.

이 네 가지 속성 사이에는 항상 다음과 같은 관계가 있습니다.

0 <= mark <= position <= limit <= capacity

아래 그림은 새로 생성된 ByteBuffer입니다.

위치는 0으로 설정되고, 용량과 상한은 10으로 설정되어 버퍼가 보유할 수 있는 마지막 바이트를 전달합니다. 태그는 처음에는 정의되지 않았습니다. 용량은 고정되어 있지만, 나머지 3가지 속성은 버퍼 사용 시 변경될 수 있습니다.

다음은 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();
}

위에 나열된 Buffer API에는 get() 또는 put() 함수가 포함되어 있지 않습니다. 모든 Buffer 클래스에는 이 두 가지 함수가 있지만 이들이 취하는 매개변수 유형과 반환하는 데이터 유형은 각 하위 클래스마다 고유하므로 최상위 Buffer 클래스에 있을 수 없습니다. 추상적으로 선언됩니다.

다음은 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);
}

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;);

다음 작업:

buffer.put(0,(byte)&#39;M&#39;).put((byte)&#39;w&#39;);

버퍼가 가득 차서 내용을 읽으려면 버퍼를 뒤집고 뒤집기 메서드를 호출해야 합니다. 다음은 뒤집기 메서드입니다. in ByteBuffer:

public final Buffer flip() {
        limit = position;
        position = 0;
        mark = -1;
        return this;
    }

rewind() 함수는 Flip()과 유사하지만 상한 속성에 영향을 주지 않습니다. 위치 값을 다시 0으로 설정합니다. rewind()를 사용하여 뒤집힌 버퍼의 데이터를 다시 읽을 수 있습니다.

hasRemaining() 메서드는 현재 버퍼의 상한에 도달했는지 여부를 반환합니다.

remaining() 메서드는 상한까지의 거리를 반환합니다.

mark() 함수가 호출되기 전에는 버퍼의 마크가 정의되지 않았으며, 호출되면 마크가 현재 위치의 값으로 설정됩니다.

reset() 함수는 위치를 현재 마커 값으로 설정합니다. 마크 값이 정의되지 않은 경우 Reset()을 호출하면 InvalidMarkException 예외가 발생합니다.

rewind( ),clear( ) 및 Flip( )은 항상 플래그를 삭제합니다. 즉, -1로 설정됩니다.

두 개의 버퍼가 동일하다고 간주되기 위한 필요 충분 조건은 다음과 같습니다.

  • 두 개체가 동일한 유형입니다. 서로 다른 데이터 유형을 포함하는 버퍼는 결코 동일하지 않으며 버퍼는 버퍼가 아닌 객체와 결코 동일하지 않습니다.

  • 두 객체 모두 남은 요소 수가 동일합니다. 버퍼의 용량은 동일할 필요가 없으며 버퍼에 남아 있는 데이터의 인덱스도 마찬가지입니다. 그러나 각 버퍼에 남아 있는 요소의 수(위치부터 상한까지)는 동일해야 합니다.

  • Get() 함수에서 반환해야 하는 나머지 데이터 요소의 순서는 각 버퍼에서 일관되어야 합니다.

버퍼 생성

//分配一个容量为 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

allocate() 또는 Wrap() 함수를 통해 생성 버퍼 일반적으로 간접 버퍼이고 간접 버퍼는 백업 배열을 사용합니다. hasArray() 이 버퍼에 액세스 가능한 지원 배열이 있는지 여부를 반환합니다.

복사 버퍼

일부 복사 버퍼 API:

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( );
}

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

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)

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

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

字节缓冲区

在 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( );

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

ByteBuffer byteBuffer = ByteBuffer.allocate (7).order (ByteOrder.BIG_ENDIAN);
CharBuffer charBuffer = byteBuffer.asCharBuffer( );

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!

数据元素视图

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);
}

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

那么 int value = buffer.getInt();

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

int value = buffer.order (ByteOrder.BIG_ENDIAN).getInt( );

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

int value = buffer.order (ByteOrder.LITTLE_ENDIAN).getInt( );

返回值 0x5E31C53B

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

위 내용은 Java NIO 버퍼의 코드 및 텍스트에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.