NIO Learning Series: buffer internal implementation mechanism

Source: Internet
Author: User

Next to the NiO Learning Series: Core concepts and basic reading and writing , this paper continues to explore and learn the internal implementation mechanism of buffers.

5. Buffer Internal Implementation
From the above study of NIO, we know that each buffer has a complex internal statistical mechanism that tracks how much data has been read and how much space can hold more data in order to manipulate the buffer. In this section we will learn about two important buffer components of NIO: state variables and access methods. Although NIO's internal statistical mechanism may seem complicated at first, you will soon see that most of the actual work has been done for you. You can do this just as you normally do with byte arrays and index variables.


1) state variable:
State variables are key to the "internal statistical mechanism" mentioned in the previous section. Each read/write operation will change the state of the buffer. By documenting and tracking these changes, the buffer can manage its own resources internally.
Each Java basic type of buffer is a subclass of the abstract class buffer, which can be found in the source code of buffer, which defines three private properties:

Java code

    1. int  position = 0 ;   

    2. private   Private  

In fact, these three attribute values can specify the state of the buffer at any time and the data it contains.
We know that every basic type of buffer layer is actually an array of that type. As in Bytebuffer, there are:

Java code

    1. Final byte [] HB;

When reading from a channel, the data being read is placed into the underlying array, and, similarly, when written to the channel, the data is written to the channel from the underlying array. Let's take a detailed description of the three variables:


   a "     position  
   position variables track how much data is written to the buffer, or how much data is read from the buffer.
   rather, when you read data from a channel into a buffer, it indicates which element of the array the next data will be placed in. For example, if you read three bytes from a channel into a buffer, the buffer's position will be set to 3, pointing to the 4th element in the array. Conversely, when you get data from a buffer for a write channel, it indicates which element of the next data comes from the array. For example, when you write 5 bytes from a buffer into a channel, the buffer's position is set to 5, which points to the sixth element of the array.


    b)     limit  
   The limit variable indicates how much data needs to be fetched (when the channel is written from the buffer), or how much space can be placed in the data (when the buffer is read from the channel).
   position is always less than or equal to limit.

   

d) Examples:

Let's take the example of copying data from an input channel to an output channel to analyze each variable in detail and how they work together:


Initial variables:
We first observe a newly created buffer, taking Bytebuffer as an example, assuming that the buffer size is 8 bytes, the Bytebuffer initial state is as follows:


Recall that limit must never be greater than capacity, in this case both values are set to 8. We illustrate this by pointing them at the end of the array (8th slot).

Let's set the position to 0 again. Indicates that if we read some data into the buffer, then the next read data goes into slot 0. If we write some data from the buffer, the next byte read from the buffer is from slot 0. The position settings are as follows:

Since the maximum data capacity of the buffer capacity not change, we can ignore it in the discussion below.

first time read:
Now we can start the read/write operation on the newly created buffer. First, read some data from the input channel into the buffer. The first read gets three bytes. They are placed in the array starting at position, where position is set to 0. After reading, the position is increased to 3, as shown below, the limit does not change.


Second read:
On the second read, we read the additional two bytes from the input channel into the buffer. These two bytes are stored in the location specified by position, and position thus increases 2,limit unchanged.


Flip:
Now we're going to write the data to the output channel. Before we do that, we have to call the flip () method. Its source code is as follows:

Java code

    1. final  buffer flip ()  {   

    2.     limit =  position;  

    3.     position  = 0 ;   

    4.     mark = -1 ;   

    5. return  }  

This method does two things that are very important:
I it sets the limit to the current position.
ii It sets the position to 0.

The previous figure shows the buffer before the flip. The following is the buffer after flip:

We can now write the data from the buffer to the channel. Position is set to 0, which means that the next byte we get is the first byte. The limit has been set to the original position, which means that it includes all the bytes previously read, and a byte is not too many.

first-time write:
At the first write, we take four bytes from the buffer and write them to the output channel. This allows the position to increase to 4, while the limit does not change as follows:


Second write:
We only have one byte left to write. Limit is set to 5 when we call Flip (), and position cannot exceed limit. So the last write operation takes a byte out of the buffer and writes it to the output channel. This allows the position to increase to 5 and keep the limit constant as follows:


clear:
The final step is to call the clear () method of the buffer. This method resets the buffer to receive more bytes. Its source code is as follows:

Java code

    1. final  buffer clear ()  {   

    2.     osition = < Span style= "Color:rgb (192, 0, 0); >0 ;   

    3.     limit =  capacity;  

    4.     mark  = -1 ;   

    5.     this ;   

    6. }&NBSP;&NBSP;

Clear does two very important things:
I set the limit to the same as capacity.
ii It sets the position to 0.
Shows the state of the buffer after the call to clear (), at which time the buffer can now receive new data.

2) Access method:
So far, we've just used buffers to transfer data from one channel to another. However, programs often need to process data directly. For example, you might want to save user data to disk. In this case, you must put the data directly into the buffer and then write the buffer to disk with the channel. Or, you may want to read user data from disk. In this case, you want to read the data from the channel into the buffer, and then examine the data in the buffer.
In fact, each of the basic types of buffers gives us a way to directly access the data in the buffer, and we use Bytebuffer as an example to analyze how to access the data in the buffer directly using its provided get () and put () methods.

a) get ()
There are four get () methods in the Bytebuffer class:

Java code

    1. byte  dst[] )   

    2. bytebuffer  Get ( byte  dst[], int  offset, byte  get ( 

The first method gets a single byte. The second and third methods read a set of bytes into an array. The fourth method gets the bytes from a specific location in the buffer. Those methods that return Bytebuffer simply return the this value of the buffer that called them.
In addition, we think that the first three get () methods are relative, and the last method is absolute. Relative means that the get () operation obeys the limit and position values, more specifically, the bytes are read from the current position, and the position is incremented after get. On the other hand, an "absolute" method ignores the limit and position values and does not affect them. In fact, it completely bypasses the statistical method of the buffer.
The methods listed above correspond to the Bytebuffer class. Other classes have an equivalent get () method, which, in addition to not processing bytes, is identical in that they deal with types that are compatible with the buffer class.

b) put ()
There are five put () methods in the Bytebuffer class:

Java code

  1. Bytebuffer put ( byte b);

  2. Bytebuffer put ( byte src[]);

  3. Bytebuffer put ( byte src[], int offset, int length);

  4. Bytebuffer put (Bytebuffer src);

  5. Bytebuffer put ( int index, byte b);

The first method writes (put) a single byte. The second and third methods write a set of bytes from an array. The fourth method writes the data from a given source bytebuffer to this bytebuffer. The Fifth method writes the bytes to a specific location in the buffer. Those methods that return Bytebuffer simply return the this value of the buffer that called them.
As with the Get () method, we will divide the put () method into "relative" or "absolute". The first four methods are relative, and the fifth method is absolute.
The method shown above corresponds to the Bytebuffer class. Other classes have an equivalent put () method, which is identical except that it is not processing bytes. They deal with types that are compatible with the buffer class.

c) typed get () and put () methods
In addition to the get () and put () methods described in the previous sections, Bytebuffer also has other methods for reading and writing different types of values, as follows:
GetByte ()
GetChar ()
Getshort ()
GetInt ()
Getlong ()
GetFloat ()
GetDouble ()
Putbyte ()
Putchar ()
Putshort ()
Putint ()
Putlong ()
Putfloat ()
Putdouble ()
In fact, each of these methods has two types: one is relative and the other is absolute. They are useful for reading formatted binary data (like the header of a file).

3) How to use?
The following internal loop summarizes the process of using buffers to copy data from an input channel to an output channel.

Java code

  1. while (true) {

  2. Buffer.clear ();

  3. int r = fcin.read (buffer);

  4. if (r==-1) {

  5. break;

  6. }

  7. Buffer.flip ();

  8. Fcout.write (buffer);

  9. }

The read () and write () calls are greatly simplified because many of the work details are completed by the buffer. The clear () and Flip () methods are used to toggle the buffer between read and write.


NIO Learning Series: buffer internal implementation mechanism

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.