Heim  >  Artikel  >  Java  >  Verwendung von Puffer in JAVA

Verwendung von Puffer in JAVA

怪我咯
怪我咯Original
2017-06-25 10:14:494887Durchsuche

Hinweis: Nachdruck aus Concurrent Programming Network, Tutorials der Java-Nio-Serie

1. Puffer

Puffer in Java NIO wird zur Interaktion mit NIO-Kanälen verwendet. Wie Sie wissen, werden Daten vom Kanal in den Puffer gelesen und vom Puffer in den Kanal geschrieben.

Ein Puffer ist im Wesentlichen ein Speicherblock, in den Daten geschrieben und aus dem dann Daten gelesen werden können. Dieser Speicher ist als NIO-Pufferobjekt verpackt und bietet eine Reihe von Methoden für den bequemen Zugriff auf diesen Speicher.

1. Grundlegende Verwendung von Buffer

Die Verwendung von Buffer zum Lesen und Schreiben von Daten erfolgt im Allgemeinen in den folgenden vier Schritten:

  1. Daten in Buffer schreiben

  2. Rufen Sie die flip()-Methode

  3. auf, um Daten aus dem Puffer zu lesen: z. B. direkt lesen oder in den Kanal lesen

  4. Rufen Sie die clear()-Methode oder die compact()-Methode

auf. Beim Schreiben von Daten in den Puffer zeichnet der Puffer auf, wie viele Daten geschrieben werden. Sobald Sie Daten lesen möchten, müssen Sie den Puffer über die Methode flip() vom Schreibmodus in den Lesemodus umschalten. Im Lesemodus können alle zuvor in den Puffer geschriebenen Daten gelesen werden.

Sobald alle Daten gelesen wurden, muss der Puffer geleert werden, damit er erneut beschrieben werden kann. Es gibt zwei Möglichkeiten, den Puffer zu löschen: Aufruf der Methode clear() oder compact(). Die Methode clear() löscht den gesamten Puffer. Die Methode compact() löscht nur die gelesenen Daten. Alle ungelesenen Daten werden an den Anfang des Puffers verschoben und neu geschriebene Daten werden nach den ungelesenen Daten im Puffer platziert.

2. Kapazität, Position und Grenze des Puffers

Ein Puffer ist im Wesentlichen ein Teil des Speichers, in den Daten geschrieben und aus dem Daten gelesen werden können. Dieser Speicher ist als NIO-Pufferobjekt verpackt und bietet eine Reihe von Methoden für den bequemen Zugriff auf diesen Speicher.

Um zu verstehen, wie Buffer funktioniert, müssen Sie mit seinen drei Eigenschaften vertraut sein:

  • Kapazität

  • Position

  • Limit

Die Bedeutung von Position und Limit hängt davon ab, ob sich der Puffer im Lesemodus oder im Schreibmodus befindet. Unabhängig davon, in welchem ​​Modus sich der Puffer befindet, ist die Bedeutung der Kapazität immer dieselbe.

Hier finden Sie eine Erklärung zu Kapazität, Position und Grenze im Lese- und Schreibmodus. Die detaillierte Erklärung befindet sich hinter der Abbildung.

Kapazität: Kapazität

Puffer hat als Speicherblock einen festen Größenwert, auch „Kapazität“ genannt. Sie können nur Kapazität in ihn schreiben , long, char und andere Typen. Sobald der Puffer voll ist, muss er geleert werden (durch Lesen von Daten oder Löschen von Daten), bevor mit dem Schreiben von Daten fortgefahren werden kann.

Position: aktuelle Position

Wenn Sie Daten in den Puffer schreiben, stellt Position die aktuelle Position dar. Der anfängliche Positionswert ist 0. Wenn Byte-, Langdaten usw. in den Puffer geschrieben werden, wird die Position zur nächsten Puffereinheit verschoben, wo Daten eingefügt werden können. Die maximale Position kann Kapazität sein – 1.

Beim Lesen von Daten werden diese auch von einer bestimmten Position aus gelesen. Wenn der Puffer vom Schreibmodus in den Lesemodus umgeschaltet wird, wird die Position auf 0 zurückgesetzt. Wenn Daten von der Position des Puffers gelesen werden, bewegt sich die Position vorwärts zur nächsten lesbaren Position.

Limit: maximale beschreibbare/lesbare Position

Im Schreibmodus gibt das Limit des Puffers die maximale Datenmenge an, die Sie in den Puffer schreiben können. Im Schreibmodus entspricht die Grenze der Kapazität des Puffers.

Wenn Sie den Puffer in den Lesemodus schalten, gibt „Limit“ die maximale Datenmenge an, die Sie lesen können. Daher wird beim Umschalten des Puffers in den Lesemodus der Grenzwert auf den Positionswert im Schreibmodus gesetzt. Mit anderen Worten, Sie können alle zuvor geschriebenen Daten lesen (die Grenze ist auf die Anzahl der geschriebenen Daten festgelegt, dieser Wert ist die Position im Schreibmodus)

3. Puffertyp

Java NIO hat die folgenden Puffertypen

  • ByteBuffer

  • MappedByteBuffer

  • CharBuffer

  • DoubleBuffer

  • FloatBuffer

  • IntBuffer

  • LongBuffer

  • ShortBuffer

Wie Sie sehen können, repräsentieren diese Puffertypen unterschiedliche Datentypen. Mit anderen Worten, die Bytes im Puffer können durch die Typen char, short, int, long, float oder double manipuliert werden.

MappedByteBuffer ist etwas Besonderes und wird in einem eigenen Kapitel besprochen.

4. Pufferzuweisung

Um ein Pufferobjekt zu erhalten, müssen Sie es zuerst zuweisen. Jede Buffer-Klasse verfügt über eine Allocate-Methode. Unten finden Sie ein Beispiel für die Zuweisung eines ByteBuffer mit einer Kapazität von 50 Bytes.

ByteBuffer buf = ByteBuffer.allocate(50);

5. Daten in den Puffer schreiben

Es gibt zwei Möglichkeiten, Daten in den Puffer zu schreiben:

  • Vom Kanal in den Puffer schreiben.

  • wird über die put()-Methode von Buffer in den Puffer geschrieben.

  • Beim Initialisieren des Puffers das Byte-Array in den Puffer einfügen

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

 

 

Die Get-Methode verfügt über viele Versionen, sodass Sie Daten auf unterschiedliche Weise aus dem Puffer lesen können. Lesen Sie beispielsweise von einer bestimmten Position aus oder lesen Sie Daten aus einem Puffer in ein Byte-Array.

7. rewind()-Methode: Position zurücksetzen

Buffer.rewind() setzt die Position auf 0 zurück, sodass Sie alle Daten im Puffer erneut lesen können. Das Limit bleibt unverändert und gibt weiterhin an, wie viele Elemente (Byte, Zeichen usw.) aus dem Puffer gelesen werden können.

8. Clear()- und Compact()-Methoden

Sobald die Daten im Puffer gelesen wurden, muss der Puffer zum erneuten Schreiben bereit sein. Dies kann über die Methoden „clear()“ oder „compact()“ erfolgen.

Wenn die Methode clear() aufgerufen wird, wird die Position auf 0 zurückgesetzt und das Limit auf den Wert der Kapazität gesetzt. Mit anderen Worten: Der Puffer wird gelöscht. Die Daten im Puffer werden nicht gelöscht, aber diese Markierungen sagen uns, wo wir mit dem Schreiben von Daten in den Puffer beginnen sollen.

Wenn sich im Puffer einige ungelesene Daten befinden und die Methode clear() aufgerufen wird, werden die Daten „vergessen“, was bedeutet, dass es keine Markierungen mehr gibt, die Ihnen sagen, welche Daten gelesen wurden und was nicht der Fall ist.

Wenn sich noch ungelesene Daten im Puffer befinden und die Daten später benötigt werden, Sie aber zuerst einige Daten schreiben möchten, dann verwenden Sie die Methode compact().

Die Methode compact() kopiert alle ungelesenen Daten an den Anfang des Puffers. Stellen Sie dann die Position direkt hinter dem letzten ungelesenen Element ein. Das Limit-Attribut ist weiterhin wie die Methode clear() auf Kapazität gesetzt. Der Puffer ist jetzt zum Schreiben von Daten bereit, ungelesene Daten werden jedoch nicht überschrieben.

9. Mark()- und Reset()-Methoden: Position markieren und Position zurückgeben

Durch Aufrufen der Buffer.mark()-Methode können Sie eine bestimmte Position im Puffer markieren. Sie können diese Position später wiederherstellen, indem Sie die Methode Buffer.reset() aufrufen. Zum Beispiel:

10. Methoden „equals()“ und „compareTo()“

Sie können die Methoden „equals()“ und „compareTo()“ verwenden, um zwei Puffer zu vergleichen.

equals()

Wenn die folgenden Bedingungen erfüllt sind, bedeutet dies, dass die beiden Puffer gleich sind:

  1. Sie haben denselben Typ (Byte, char, int usw. ).

  2. Die Anzahl der im Puffer verbleibenden Bytes, Zeichen usw. ist gleich.

  3. Alle verbleibenden Bytes, Zeichen usw. im Puffer sind gleich.

Wie Sie sehen können, vergleicht „equals“ nur einen Teil des Puffers, nicht jedes Element darin. Tatsächlich werden nur die verbleibenden Elemente im Puffer verglichen.

compareTo()-Methode

compareTo()-Methode vergleicht die verbleibenden Elemente (Byte, Zeichen usw.) von zwei Puffern. Wenn die folgenden Bedingungen erfüllt sind, wird ein Puffer als „kleiner als“ betrachtet " der andere Puffer:

  1. Das erste ungleiche Element ist kleiner als das entsprechende Element im anderen Puffer.

  2. Alle Elemente sind gleich, aber der erste Puffer ist vor dem anderen erschöpft (der erste Puffer enthält weniger Elemente als der andere).

(Übersetzung: Die übrigen Elemente sind die Elemente von Position bis Limit)

2. Buffer's Scatter/Gather

Die sogenannten Scatter und Gather sind Kanäle, die mehreren Caches entsprechen: Lesen eines Kanals in mehrere Caches, Schreiben mehrerer Caches in einen Kanal

Java NIO beginnt mit der Unterstützung von Scatter/Gather, Scatter/Gather. Wird zur Beschreibung des Vorgangs verwendet des Lesens oder Schreibens von Channel (Anmerkung des Übersetzers: Channel wird auf Chinesisch oft als Kanal übersetzt).

Streulesen vom Kanal bedeutet, dass die gelesenen Daten während des Lesevorgangs in mehrere Puffer geschrieben werden. Daher „verteilt“ der Kanal die vom Kanal gelesenen Daten auf mehrere Puffer.

Das Sammeln von Daten in den Kanal bedeutet, dass während eines Schreibvorgangs Daten aus mehreren Puffern in denselben Puffer geschrieben werden. Daher „sammelt“ der Kanal die Daten speichert Daten in mehreren Puffern und sendet sie an den Kanal.

Streuen/Sammeln wird häufig in Situationen verwendet, in denen die übertragenen Daten separat verarbeitet werden müssen. Wenn Sie beispielsweise eine Nachricht übertragen, die aus einem Nachrichtenkopf und einem Nachrichtenhauptteil besteht, können Sie den Nachrichtenhauptteil und den Nachrichtenkopf streuen in verschiedene Puffer, sodass Sie den Nachrichtenkopf und den Nachrichtentext problemlos verarbeiten können.

Scattering Reads
Scattering Reads bedeutet, dass Daten von einem Kanal in mehrere Puffer gelesen werden. Wie unten beschrieben:

Java NIO: Scattering Read

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

 

Das obige ist der detaillierte Inhalt vonVerwendung von Puffer in JAVA. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn