Introduction to Java NiO (ii): Buffer interior details

Source: Internet
Author: User

Introduction to Java NIO (ii) buffer interior details

Overview

This article describes two important buffer components in NIO: state variables and access Methods (accessor).

State variables are key to the "internal statistical mechanism" mentioned in the previous article. 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.

When the data is read from the channel, the data is put into the buffer. In some cases, you can write this buffer directly to another channel, but in general you will need to look at the data as well. This is done using the Access method get (). Similarly, if you want to put the raw data into a buffer, use the access method put ().

In this section, you will learn about the state variables in NIO and the content of access methods. We will describe each component and give you a chance to see its actual application. 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 may be accustomed to bookkeeping by hand-using byte arrays and index variables, which are now handled internally in NIO.

State variables

You can specify the state of a buffer at any time with three values:

    • Position

    • Limit

    • Capacity

Together, these three variables can track the state of the buffer and the data it contains. We will analyze each variable in detail in the subsections below, and also describe how they fit into the typical read/write (input/output) process. In this example, we assume that we want to copy data from an input channel to an output channel.

1.Position

You can recall that the buffer is actually a glorified array. When reading from a channel, you put the data you read into the underlying array. The position variable tracks how much data has been written. More precisely, it specifies which element of the array the next byte will be placed in. Therefore, if you read three bytes from the channel into the buffer, then the position of the buffer will be set to 3, pointing to the fourth element in the array.

Similarly, when you write to a channel, you get the data from the buffer. The position value keeps track of how much data is fetched from the buffer. To be more precise, it specifies which element of the array the next byte is coming from. So if you write 5 bytes from the buffer to the channel, then the buffer's position will be set to 5, pointing to the sixth element of the array.

2.Limit

Limit variables indicate 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.

3.Capacity

The capacity of the buffer indicates the maximum amount of data that can be stored in the buffer. In fact, it specifies the size of the underlying array-or at least specifies the capacity of the underlying array that we are allowed to use.

Limit must not be greater than capacity.

We first look at a newly created buffer. For the purposes of this example, we assume that the total capacity of this buffer is 8 bytes. The status of the Buffer 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, if there is a 8th slot, where the 8th slot is located.

The position is set to 0. If we read some data into the buffer, then the next read of the 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 capacity does 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:

Limit has not changed.

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 by 2:

Limit has not changed.

Flip

Now we're going to write the data to the output channel. Before we do that, we have to call the flip () method. This method does two things that are very important:

    1. It sets the limit to the current position.

    2. It sets the position to 0.

The figure in the previous section 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. Clear does two very important things:

    1. It sets the limit to the same as capacity.

    2. It sets the position to 0.

Shows the state of the buffer after the call to clear ():

The buffer can now receive new data.

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.

At the end of this section, we will analyze in detail how to use the Get () and put () methods of the Bytebuffer class to directly access the data in the buffer.

Get () method

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

    1. byte get ();

    2. Bytebuffer get (byte dst[]);

    3. Bytebuffer get (byte dst[], int offset, int length);

    4. BYTE get (int index);

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. The 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.

Put () method

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

    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.

To give a simple example, the following code shows:

1 //Typesinbytebuffer2 3 ImportJava.nio.*;4 5  Public classTypesinbytebuffer {6   Static  Public voidMain (string[] args)throwsException {7Bytebuffer Buffer=bytebuffer.allocate (64);8Bytebuffer Buffer2=bytebuffer.allocate (1024);9     TenBuffer.putint (30); One buffer.putdouble (Math.PI); A Buffer.flip (); - //System.out.println (Buffer.getint ()); - //System.out.println (Buffer.getdouble ()); the //buffer.clear (); -      - buffer2.put (buffer); - Buffer2.flip (); + System.out.println (Buffer2.getint ()); - System.out.println (Buffer2.getdouble ()); +   } A}

Typed get () and put () methods

    • 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).

1 //Typesinbytebuffer2 3 ImportJava.nio.*;4 5  Public classTypesinbytebuffer {6   Static  Public voidMain (string[] args)throwsException {7Bytebuffer Buffer=bytebuffer.allocate (64);8 9Buffer.putint (30);Ten buffer.putdouble (Math.PI); One Buffer.flip (); A System.out.println (Buffer.getint ()); - System.out.println (Buffer.getdouble ()); - buffer.clear (); the   } -}

Use of buffers: an internal loop

The following internal loop summarizes the process of using buffers to copy data from an input channel to an output channel.

 1  while  ( true        Buffer.clear ();  3  int  R = 4  if  (r==-1   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.

Introduction to Java NiO (ii): Buffer interior details

Related Article

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.