codestory

Die Anleitung zu Java Buffer

  1. Buffer
  2. Buffer Methods
  3. capacity()
  4. position()
  5. position(int newPosition)
  6. limit()
  7. limit(int newLimit)
  8. mark()
  9. reset()
  10. clear()
  11. flip()
  12. rewind()
  13. remaining()
  14. hasRemaining()
  15. slice()
  16. duplicate()
  17. array()
  18. hasArray()
  19. arrayOffset()
  20. isReadOnly()
  21. isDirect()

1. Buffer

Java NIO Buffer repräsentiert einen Container mit einer festen Kapazität zum Speichern primitiver Daten. Es wird oft in Verbindung mit Java NIO Channel(s) verwendet. Insbesondere werden Daten aus Channel in Buffer gelesen oder Daten aus Buffer in Channel geschrieben.
public abstract class Buffer extends Object
Die Hierarchie von Klassen und Interface in Bezug auf Java NIO Buffer:
  • ByteBuffer
  • ShortBuffer
  • IntBuffer
  • LongBuffer
  • FloatBuffer
  • DoubleBuffer
  • CharBuffer
  • MappedByteBuffer
  • ByteOrder
Die Beziehung zwischen Channel und Buffer ähnelt der Beziehung zwischen einer Schüssel und einem Löffel. Der Löffel kann als kleiner Behälter verwendet werden, um den Zucker aus der Schüssel zu entnehmen und er kann auch als kleiner Behälter verwendet werden, um den Zucker von außen in die Schüssel zu geben. Somit fungiert der Löffel als Buffer und die Schüssel als Channel.
Capacity, limit, position und mark sind die 4 wichtigsten Begriffe vonJava NIO Buffer, die im Folgenden näher erläutert werden. Sowohl im Lese- als auch im Schreibmodus bewegt sich der Cursor immer nach rechts.

2. Buffer Methods

public final int capacity()
 
public final int position()   
public Buffer position(int newPosition)  

public final int limit()   
public Buffer limit(int newLimit)

public Buffer mark()
public Buffer reset()  
public Buffer clear()  
public Buffer flip()   
public 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();
public abstract Buffer slice();
public abstract Buffer duplicate();

3. capacity()

public final int capacity()
Die Methode capacity() gibt die Kapazität dieses Buffer zurück.
Obwohl Sie nur Elemente von Index 0 bis limit-1 lesen oder schreiben können, können Sie, wenn Sie limit = capacity setzen, auf alle Elemente des Buffer zugreifen (lesen, schreiben).

4. position()

public final int position()
Gibt die aktuelle Position des Cursors zurück. Sowohl Lese- als auch Schreiboperationen bewegen den Cursor an das Ende des Buffer. Der zurückgegebene Wert ist immer kleiner oder gleich dem limit.
  • 0 <= mark <= position <= limit <= capacity

5. position(int newPosition)

public Buffer position(int newPosition)
Legen Sie die neue Position für den Zeiger fest.
  • newPostion muss größer oder gleich 0 und kleiner oder so gleich wie limit sein.
  • Wenn newPosition < mark, wird mark verworfen.

6. limit()

public final int limit()
Gibt das limit dieses Buffer zurück.
Buffer unterstützt nur das Lesen und Schreiben von Elementen am Index 0 bis limit-1. Die andere Elemente am Index limit bis capacity-1 sind deaktiviert. Sie können jedoch limit = capacity festlegen, um auf alle Elemente des Buffer zugreifen (lesen oder schreiben) zu können.
  • 0 <= mark <= position <= limit <= capacity
Im Beispiel unten: Ein CharBuffer mit der capacity = 10 und dem limit = 7, Sie können nur von Elementen mit Index von 0 bis 6 lesen und in sie schreiben. Eine Verletzung einer Ausnahme wird ausgelöst.
Buffer_limit_ex1.java
// Allocate a character type buffer.
CharBuffer buffer = CharBuffer.allocate(10); // capacity = 10

buffer.limit(7); // limit = 7

String text = "abcdefghij";
System.out.println("Input text: " + text);
System.out.println("Text length: " + text.length()); // 10

for (int i = 0; i < text.length(); i++) {
    char chr = text.charAt(i);
    
    // put character in buffer.
    buffer.put(chr);
    System.out.println(i + ". put: " + chr);
}
Output:
Input text: abcdefghij
Text length: 10
0. put: a
1. put: b
2. put: c
3. put: d
4. put: e
5. put: f
6. put: g
Exception in thread "main" java.nio.BufferOverflowException
    at java.base/java.nio.Buffer.nextPutIndex(Buffer.java:665)
    at java.base/java.nio.HeapCharBuffer.put(HeapCharBuffer.java:199)
    at org.o7planning.buffer.ex.Buffer_limit_ex1.main(Buffer_limit_ex1.java:21)

7. limit(int newLimit)

public Buffer limit(int newLimit)
Stellen Sie den neuen limit für diesen Buffer ein. newLimit muss kleiner als capacity sein, andernfalls wird IllegalArgumentException geworfen.
  • Wenn newLimit < position, wird postion auf newLimit gesetzt.
  • Bei newLimit < mark, wird mark verworfen (discard).
Zum Beispiel:
Buffer_limit_newLimit_ex1.java
// Allocate a character type buffer.
CharBuffer buffer = CharBuffer.allocate(10); // capacity = 10

System.out.printf("Buffer capacity: %d%n%n", buffer.capacity()); // 10

buffer.limit(9); // limit = 9
System.out.printf("Buffer limit: %d, position: %d%n%n", buffer.limit(), buffer.position());

System.out.println("Set newPostion: 8");
buffer.position(8);

System.out.printf("Buffer limit: %d, position: %d%n%n", buffer.limit(), buffer.position());

System.out.println("Set newLimit: 7");
// Set limit = 7.
buffer.limit(7);

System.out.printf("Buffer limit: %d, position: %d%n", buffer.limit(), buffer.position());
Output:
Buffer capacity: 10

Buffer limit: 9, position: 0

Set newPostion: 8
Buffer limit: 9, position: 8

Set newLimit: 7
Buffer limit: 7, position: 7

8. mark()

public Buffer mark()
Die Methode mark() wird verwendet, um die aktuelle Position des Cursors zu markieren. Bei der Manipulation von Buffer kann sich die Position des Cursors ändern. Der Aufruf der Methode reset() hilft dem Cursor, an die zuvor markierte Position zurückzukehren.
  • 0 <= mark <= position <= limit <= capacity
mark wird in den folgenden Fällen verworfen:
  • Rufen Sie die Methode setPosition(newPosition) mit newPosition < mark auf.
  • Rufen Sie die Methode setLimit(newLimit) mit newLimit < mark auf.
  • Rufen Sie die Methode clear(), rewind() oder flip() auf.

9. reset()

public Buffer reset()
Die Methode reset() wird verwendet, um den Cursor an die zuvor markierte Position zurückzubringen. (Siehe die Methode mark()).
Diese Methode kann eine InvalidMarkException auslösen, wenn mark nicht definiert ist oder verworfen wurde.
mark wird in den folgenden Fällen verworfen:
  • Rufen Sie die Methode setPosition(newPosition) mit newPosition < mark auf.
  • Rufen Sie die Methode setLimit(newLimit) mit newLimit < mark auf.
  • Rufen Sie die Methode clear(), rewind() oder flip() auf.
Zum Beispiel:
Buffer_reset_ex1.java
CharBuffer buffer = CharBuffer.allocate(10); // capacity = 10

System.out.println("Set newPostion: 5");
buffer.position(5);

System.out.println("Mark current position!");
buffer.mark(); // marked position = 5

System.out.println("Call buffer.get() twice!");
char ch1 = buffer.get();
char ch2 = buffer.get();

System.out.printf("Position: %d%n%n", buffer.position()); // position = 7

System.out.println("Reset!");
buffer.reset();

System.out.printf("Position: %d%n%n", buffer.position()); // position = 5
Output:
Set newPostion: 5
Mark current position!
Call buffer.get() twice!
Position: 7

Reset!
Position: 5

10. clear()

public Buffer clear()
Die Methode clear() setzt position = 0; limit = capacity, verwerfen Sie mark und geben Sie Buffer zurück. Das Aufrufen dieser Methode wirkt sich nicht auf die Daten im Buffer aus.
Zum Beispiel:
Buffer_clear_ex1.java
CharBuffer buffer = CharBuffer.allocate(7); // capacity = 7

// Write data to buffer:
buffer.put('A');
buffer.put('B');

buffer.position(3); // Set position to 3.
buffer.limit(5); // Set limit to 5.

System.out.printf("buffer, capcity: %d, limit: %d, position: %d%n%n", //
        buffer.capacity(), buffer.limit(), buffer.position());

System.out.println("Clear...");
buffer.clear();

System.out.printf("buffer, capcity: %d, limit: %d, position: %d%n%n", //
        buffer.capacity(), buffer.limit(), buffer.position());

// Read data in buffer:
while (buffer.hasRemaining()) {
    char chr = buffer.get();
    System.out.println(chr + " --> " + (int) chr); // char and code.
}
Output:
buffer, capcity: 7, limit: 5, position: 3

Clear...
buffer, capcity: 7, limit: 7, position: 0

A --> 65
B --> 66
--> 0
--> 0
--> 0
--> 0
--> 0

11. flip()

public Buffer flip()
Die Methode flip() setzt limit = aktuelle position , position = 0 und gibt diesen Buffer zurück und verwirft mark. (Siehe Abbildung unten).
Das folgende Beispiel entspricht der obigen Abbildung:
Buffer_flip_ex1.java
CharBuffer buffer = CharBuffer.allocate(10); // capacity = 10

System.out.printf("Position: %d, Limit: %d, Capacity: %d%n%n",
        buffer.position(), buffer.limit(), buffer.capacity());

System.out.println("Write 3 characters to buffer\n");
for(char ch : new char[] {'A','B','C'}) {
    buffer.put(ch);
}
System.out.printf("Position: %d, Limit: %d, Capacity: %d%n%n",
        buffer.position(), buffer.limit(), buffer.capacity());

System.out.println("Set limit = 7, position = 5\n");
buffer.limit(7);
buffer.position(5);

System.out.printf("Position: %d, Limit: %d, Capacity: %d%n%n",
        buffer.position(), buffer.limit(), buffer.capacity());   

System.out.println(" --- flip() --- \n");
buffer.flip();  

System.out.printf("Position: %d, Limit: %d, Capacity: %d",
        buffer.position(), buffer.limit(), buffer.capacity());
Output:
Position: 0, Limit: 10, Capacity: 10

Write 3 characters to buffer

Position: 3, Limit: 10, Capacity: 10

Set limit = 7, position = 5

Position: 5, Limit: 7, Capacity: 10

 --- flip() ---

Position: 0, Limit: 5, Capacity: 10
Die Methode flip() wird normalerweise verwendet, nachdem das Schreiben von Daten in Buffer abgeschlossen ist, wodurch der Cursor auf den Index 0 bewegt wird. Bereit zum Auslesen nützlicher Daten in Buffer. (Sehen Sie Abbildungen und Beispiele unten).
Buffer_flip_ex2.java
CharBuffer buffer = CharBuffer.allocate(5); // capacity = 5  

// WRITE MODE:
System.out.println("Write 3 characters to buffer\n");
for(char ch : new char[] {'A','B','C'}) {
    buffer.put(ch);
}  
// (Now position = 3, limit = 5, capacity = 5).
System.out.println(" --- flip() --- \n");
buffer.flip();

// READ MODE:
// (Now position = 0, limit = 3, capacity = 5).
while(buffer.position() < buffer.limit()) {
   char ch = buffer.get();
   System.out.println(ch);
}
Output:
Write 3 characters to buffer

 --- flip() ---

A
B
C

12. rewind()

public Buffer rewind()
Die Methode rewind() wird verwendet, um diesen Buffer zurückzuspulen, dh sie setzt position = 0 und verwirft die mark.

13. remaining()

public final int remaining()
Gibt die Anzahl der Elemente zwischen position und limit-1 zurück.

14. hasRemaining()

public final boolean hasRemaining()
Gibt true zurück, wenn zwischen position und limit-1 Elemente vorhanden sind. Andernfalls wird false zurückgegeben.

15. slice()

public abstract Buffer slice();
Gibt einen neuen Buffer zurück, der ein teilweiser Snapshot dieses Buffer ist. Der neue Buffer enthält die Elemente zwischen position und limit-1 dieses Buffer. Die markierte Position des neuen Buffer ist nicht definiert, position des neuen Buffer ist 0. (Sehen Sie Abbildung unten).
Diese beiden Buffer stehen in Beziehung zueinander, Datenänderungen auf dem einen Buffer werden auf dem anderen Buffer sichtbar und umgekehrt. mark, position, limit, capacity dieser beiden Buffer(s)sind voneinander unabhängig.
Zum Beispeil:
Buffer_slice_ex1.java
CharBuffer buffer1 = CharBuffer.allocate(10); // capacity = 10  

// Write data to buffer1:
buffer1.put('A');
buffer1.put('B');
buffer1.put('C');

buffer1.position(1); // Set position to 1.
buffer1.limit(7); // Set limit to 7.

CharBuffer buffer2 = buffer1.slice();

System.out.printf("buffer2, capcity: %d, limit: %d, position: %d%n%n",
              buffer2.capacity(), buffer2.limit(), buffer2.position());

// Change data in buffer2:
buffer2.put('D');
buffer2.put('E');
buffer2.put('F');

//
buffer1.position(0);
buffer1.limit(4);
// Read data in buffer1:
while(buffer1.hasRemaining()) {
    System.out.println(buffer1.get());
}
Output:
buffer2, capcity: 6, limit: 6, position: 0

A
D
E
F

16. duplicate()

public abstract Buffer duplicate();
Gibt einen neuen Buffer zurück, der eine Momentaufnahme dieses Buffer ist.
Die Daten des neuen Buffer sind die Daten dieses Buffer. Änderungen an den Daten dieses Buffer werden im neuen Buffer sichtbar und umgekehrt; die Werte von position, limit und mark der beiden Buffer(s) sind unabhängig. Beim Neuanlegen haben zwei Buffer(s) die gleichen Werte position, limit, mark.
Zum Beispiel:
Buffer_duplicate_ex1.java
CharBuffer buffer1 = CharBuffer.allocate(10); // capacity = 10  

// Write data to buffer1:
buffer1.put('A');
buffer1.put('B');
buffer1.put('C');

buffer1.position(1); // Set position to 1.
buffer1.limit(7); // Set limit to 7.

CharBuffer buffer2 = buffer1.duplicate();

System.out.printf("buffer2, capcity: %d, limit: %d, position: %d%n%n",
              buffer2.capacity(), buffer2.limit(), buffer2.position());

// Change data in buffer2:
buffer2.put('D');
buffer2.put('E');
buffer2.put('F');

//
buffer1.position(0);
buffer1.limit(4);
// Read data in buffer1:
while(buffer1.hasRemaining()) {
    System.out.println(buffer1.get());
}
Output:
buffer2, capcity: 10, limit: 7, position: 1

A
D
E
F

17. array()

public abstract Object array(); // Optional Operation.
Gibt ein Array zurück, das die Elemente dieses Buffer enthält, wenn dieser Buffer tatsächlich Arrays als Technik zum Speichern der Elemente verwendet. Dies ist eine optionale Operation, die in der Unterklasse von Buffer möglicherweise nicht unterstützt wird. Wenn diese Methode nicht unterstützt wird, wird eine UnsupportedOperationException ausgelöst. Überprüfen Sie, ob dieser Buffer Arrays unterstützt, indem Sie die Methode hasArray() verwenden.
Die meisten der im JDK verfügbaren Unterklassen von Buffer verwenden ein internes Array, um die Elemente zu speichern.
Class
Has Array?
ByteBuffer
true
MappedByteBuffer
true
ShortBuffer
true
IntBuffer
true
FloatBuffer
true
LongBuffer
true
DoubleBuffer
true
CharBuffer
true
Zum Beispiel:
Buffer_array_ex1.java
CharBuffer charBuffer = CharBuffer.allocate(5); // capacity = 5

// Write data to charBuffer:
charBuffer.put('A');
charBuffer.put('B');
charBuffer.put('C');

boolean hasArray = charBuffer.hasArray(); // true

if(hasArray)  {
    char[] charArray = charBuffer.array();
    System.out.println("charArray.length: " + charArray.length);  // 5
    for(char ch: charArray)  {
        System.out.println(ch + " --> " + (int)ch);    // char and code
    }
}
Output:
charArray.length: 5
A --> 65
B --> 66
C --> 67
--> 0
--> 0

18. hasArray()

public abstract boolean hasArray();
Gibt true zurück, wenn dieser Buffer Arrays als Technik zum Speichern von Elementen verwendet, andernfalls wird false zurückgegeben. Dies ist eine optionale Operation, die in der Unterklasse von Buffer möglicherweise nicht unterstützt wird.
Die meisten der im JDK verfügbaren Unterklassen von Buffer verwenden ein internes Array, um die Elemente zu speichern.
Class
Has Array?
ByteBuffer
true
MappedByteBuffer
true
ShortBuffer
true
IntBuffer
true
FloatBuffer
true
LongBuffer
true
DoubleBuffer
true
CharBuffer
true

19. arrayOffset()

public abstract int arrayOffset();

20. isReadOnly()

public abstract boolean isReadOnly();
Überprüfen Sie, ob dieser Buffer schreibgeschützt (read-only) ist oder nicht. Dies ist ein optionaler Vorgang, der in der Unterklasse von Buffer möglicherweise nicht unterstützt wird, und eine UnsupportedOperationException wird ausgelöst.
Die meisten der im JDK verfügbaren Unterklassen von Buffer unterstützen sowohl den Lese- als auch den Schreibmodus (standardmäßig):
Class
Read-Only
by default?
Support
Read-Only?
ByteBuffer
false
true
MappedByteBuffer
false
true
ShortBuffer
false
true
IntBuffer
false
true
FloatBuffer
false
true
LongBuffer
false
true
DoubleBuffer
false
true
CharBuffer
false
true
Zum Beispiel:
Buffer_isReadOnly_ex1.java
Buffer b1 = ByteBuffer.allocate(10);
Buffer b2 = MappedByteBuffer.allocate(10);
Buffer b3 = ShortBuffer.allocate(10);
Buffer b4 = IntBuffer.allocate(10);
Buffer b5 = FloatBuffer.allocate(10);
Buffer b6 = LongBuffer.allocate(10);
Buffer b7 = DoubleBuffer.allocate(10);
Buffer b8 = CharBuffer.allocate(10);

Buffer[] buffers = new Buffer[] { b1, b2, b3, b4, b5, b6, b7, b8 };

for (Buffer buffer : buffers) {
    System.out.println(buffer.getClass().getSimpleName() + " --> " + buffer.isReadOnly());
}
Output:
HeapByteBuffer --> false
HeapByteBuffer --> false
HeapShortBuffer --> false
HeapIntBuffer --> false
HeapFloatBuffer --> false
HeapLongBuffer --> false
HeapDoubleBuffer --> false
HeapCharBuffer --> false
Zum Beispiel: Erstellen Sie einen schreibgeschützten CharBuffer:
Buffer_isReadOnly_ex2.java
CharBuffer charBuffer = CharBuffer.allocate(10); // capacity = 10
// Write data to charBuffer.
charBuffer.put('A');
charBuffer.put('B');
charBuffer.put('C');

// Create a read-only CharBuffer.
CharBuffer readOnlyBuffer = charBuffer.asReadOnlyBuffer();

System.out.println("Write data to read-only buffer:");
readOnlyBuffer.put('D'); // ==> java.nio.ReadOnlyBufferException
Output:
Write data to read-only buffer:
Exception in thread "main" java.nio.ReadOnlyBufferException
    at java.base/java.nio.HeapCharBufferR.put(HeapCharBufferR.java:202)
    at org.o7planning.buffer.ex.Buffer_isReadOnly_ex2.main(Buffer_isReadOnly_ex2.java:18)
Zum Beispiel: Erstellen Sie die anderen schreibgeschutzten Buffer wie: ByteBuffer, MappedByteBuffer, ShortBuffer, ...
Buffer_isReadOnly_ex3.java
package org.o7planning.buffer.ex;

import java.io.IOException;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.DoubleBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.LongBuffer;
import java.nio.MappedByteBuffer;
import java.nio.ShortBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

public class Buffer_isReadOnly_ex3 {

    public static void main(String[] args) throws IOException {
        ByteBuffer b1 = ByteBuffer.allocate(10);
        
        //
        Path pathToWrite = Paths.get("/Volumes/Data/test/out-file.txt");
        FileChannel fileChannel = (FileChannel) Files.newByteChannel(pathToWrite, //
                                                StandardOpenOption.READ,
                                                StandardOpenOption.WRITE,
                                                StandardOpenOption.TRUNCATE_EXISTING);
        
        CharBuffer charBuffer = CharBuffer.wrap("This will be written to the file");
        MappedByteBuffer b2 = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, charBuffer.length());
        //
        ShortBuffer b3 = ShortBuffer.allocate(10);
        IntBuffer b4 = IntBuffer.allocate(10);
        FloatBuffer b5 = FloatBuffer.allocate(10);
        LongBuffer b6 = LongBuffer.allocate(10);
        DoubleBuffer b7 = DoubleBuffer.allocate(10);
        CharBuffer b8 = CharBuffer.allocate(10);
        
        Buffer[] buffers = new Buffer[] { b1, b2, b3, b4, b5, b6, b7, b8 };
        for (Buffer buffer : buffers) {
            System.out.println(buffer.getClass().getSimpleName() + " --> " + buffer.isReadOnly());
        }
        System.out.println(" --------- ");
        
        ByteBuffer b1r = b1.asReadOnlyBuffer();
        MappedByteBuffer b2r = (MappedByteBuffer) b2.asReadOnlyBuffer();
        ShortBuffer b3r = b3.asReadOnlyBuffer();
        IntBuffer b4r = b4.asReadOnlyBuffer();
        FloatBuffer b5r = b5.asReadOnlyBuffer();
        LongBuffer b6r = b6.asReadOnlyBuffer();
        DoubleBuffer b7r = b7.asReadOnlyBuffer();
        CharBuffer b8r = b8.asReadOnlyBuffer();
        
        Buffer[] readOnlyBuffers = new Buffer[] { b1r, b2r, b3r, b4r, b5r, b6r, b7r, b8r };
        
        for (Buffer buffer : readOnlyBuffers) {
            System.out.println(buffer.getClass().getSimpleName() + " --> " + buffer.isReadOnly());
        }
    }
}
Output:
HeapByteBuffer --> false
DirectByteBuffer --> false
HeapShortBuffer --> false
HeapIntBuffer --> false
HeapFloatBuffer --> false
HeapLongBuffer --> false
HeapDoubleBuffer --> false
HeapCharBuffer --> false
 ---------
HeapByteBufferR --> true
DirectByteBufferR --> true
HeapShortBufferR --> true
HeapIntBufferR --> true
HeapFloatBufferR --> true
HeapLongBufferR --> true
HeapDoubleBufferR --> true
HeapCharBufferR --> true

21. isDirect()

public abstract boolean isDirect();
No ADS