Java NIO编程

Java NIO编程

参考资料:http://tutorials.jenkov.com/java-nio/channels.html

Java NIO Channel

Java NIO Channels are similar to streams with a few differences: // NIO Channels 和 Streams 相似,但有些不同

  • You can both read and write to a Channels. Streams are typically one-way (read or write). // 您可以对Channel读写操作,Stream通常是单向读或者写

  • Channels can be read and written asynchronously. // Channel 可以异步的读写

  • Channels always read to, or write from, a Buffer. // Channel 总是读写到Buffer

As mentioned above, you read data from a channel into a buffer, and write data from a buffer into a channel. Here is an illustration of that:


Image.png
Channel Implementations

Here are the most important Channel implementations in Java NIO:

  • FileChannel
  • DatagramChannel
  • SocketChannel
  • ServerSocketChannel

The FileChannel reads data from and to files.
The DatagramChannel can read and write data over the network via UDP.
The SocketChannel can read and write data over the network via TCP.
The ServerSocketChannel allows you to listen for incoming TCP connections, like a web server does. For each incoming connection a SocketChannel is created.

Using a Buffer to read and write data typically follows this little 4-step process:

  • Write data into the Buffer

  • Call buffer.flip()

  • Read data out of the Buffer

  • Call buffer.clear() or buffer.compact()

When you write data into a buffer, the buffer keeps track of how much data you have written. Once you need to read the data, you need to switch the buffer from writing mode into reading mode using the flip()method call. In reading mode the buffer lets you read all the data written into the buffer.
当您从channel把数据写入缓冲区时,缓冲区将跟踪您已写入了多少数据。一旦需要读取数据,就需要使用flip()方法调用将缓冲区从写模式切换到读模式。在读取模式中,缓冲区允许您读取写入缓冲区的所有数据

Once you have read all the data, you need to clear the buffer, to make it ready for writing again. You can do this in two ways: By calling clear() or by calling compact(). The clear() method clears the whole buffer. The compact() method only clears the data which you have already read. Any unread data is moved to the beginning of the buffer, and data will now be written into the buffer after the unread data
读取所有数据之后,需要清除缓冲区,以便再次写入数据。有两种方法可以做到这一点:调用clear()或调用compact()。clear()方法清除整个缓冲区。compact()方法只清除您已经读取的数据。任何未读的数据都被移动到缓冲区的开头,现在数据将在未读数据之后写入缓冲区

Buffer Capacity, Position and Limit

A buffer is essentially a block of memory into which you can write data, which you can then later read again. This memory block is wrapped in a NIO Buffer object, which provides a set of methods that makes it easier to work with the memory block.
A Buffer has three properties you need to be familiar with, in order to understand how a Buffer works. These are:

  • capacity -- 容量
  • position
  • limit -- 理解上限

The meaning of position and limit depends on whether the Buffer is in read or write mode. Capacity always means the same, no matter the buffer mode.
Here is an illustration of capacity, position and limit in write and read modes.
The explanation follows in the sections after the illustration.
[图片上传失败...(image-f9eb7e-1577000155577)]

Capacity
Being a memory block, a Buffer has a certain fixed size, also called its "capacity". You can only write capacity bytes, longs, chars etc. into the Buffer. Once the Buffer is full, you need to empty it (read the data, or clear it) before you can write more data into it.
Position
When you write data into the Buffer, you do so at a certain position. Initially the position is 0. When a byte, long etc. has been written into the Buffer the position is advanced to point to the next cell in the buffer to insert data into. Position
can maximally become capacity - 1.When you read data from a Buffer you also do so from a given position. When you flip a Buffer from writing mode to reading mode, the position is reset back to 0. As you read data from the Buffer you do so from position, and position is advanced to next position to read.
Limit
In write mode the limit of a Buffer is the limit of how much data you can write into the buffer. In write mode the limit is equal to the capacity of the Buffer.When flipping the Buffer into read mode, limit means the limit of how much data you can read from the data. Therefore, when flipping a Buffer into read mode, limit is set to write position of the write mode. In other words, you can read as many bytes as were written (limit is set to the number of bytes written, which is marked by position).

Buffer Types
Java NIO comes with the following Buffer types:

  • ByteBuffer
  • MappedByteBuffer
  • CharBuffer
  • DoubleBuffer
  • FloatBuffer
  • IntBuffer
  • LongBuffer
  • ShortBuffer

As you can see, these Buffer types represent different data types. In other words, they let you work with the bytes in the buffer as char, short, int, long, float or double instead.
The MappedByteBuffer is a bit special, and will be covered in its own text.

Allocating a Buffer

To obtain a Buffer object you must first allocate it. Every Buffer class has an allocate() method that does this. Here is an example showing the allocation of a ByteBuffer,
每个Buffer 类型都有一个allocate()分配的方法
with a capacity of 48 bytes:

ByteBuffer buf = ByteBuffer.allocate(48);
CharBuffer buf = CharBuffer.allocate(1024);
Writing Data to a Buffer

You can write data into a Buffer in two ways: // 写数据的两种方法

  1. Write data from a Channel into a Buffer // 从channel 写入
int bytesRead = inChannel.read(buf);
  1. Write data into the Buffer yourself, via the buffer's put() methods. // 自己将数据调用put写到 buffer中
buf.put(127);

There are many other versions of the put() method, allowing you to write data into the Buffer in many different ways. For instance, writing at specific positions, or writing an array of bytes into the buffer. See the JavaDoc for the concrete buffer implementation for more details

flip()

The flip() method switches a Buffer from writing mode to reading mode. Calling flip() sets the position back to 0, and sets the limit to where position just was.
flip()方法将缓冲区从写模式切换到读模式。调用flip()将position设置为0,并将limit设置为之前position所在的位置。

In other words, position now marks the reading position, and limit marks how many bytes, chars etc. were written into the buffer - the limit of how many bytes, chars etc. that can be read.
换句话说,position现在标记读取位置,limit标记写入缓冲区的字节数、字符数等—可以读取的字节数、字符数等的上限。

Reading Data from a Buffer

There are two ways you can read data from a Buffer.

  1. Read data from the buffer into a channel.
int bytesWritten = inChannel.write(buf);
  1. Read data from the buffer yourself, using one of the get() methods.
byte aByte = buf.get()

There are many other versions of the get() method, allowing you to read data from the Buffer in many different ways. For instance, reading at specific positions, or reading an array of bytes from the buffer. See the JavaDoc for the concrete buffer implementation for more details.

rewind()

The Buffer.rewind() sets the position back to 0, so you can reread all the data in the buffer. The limitremains untouched, thus still marking how many elements (bytes, chars etc.) that can be read from the Buffer.
rewind 设置 position为0,limit 保持不变,仍然还是可以从缓冲区读取的元素的数量

flip() 和 rewind() 的区别, 是否有对limit的设值; rewind:倒带, 重新再从头开始读;
源码:

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

Once you are done reading data out of the Buffer you have to make the Buffer ready for writing again. You can do so either by calling clear() or by calling compact().
If you call clear() the position is set back to 0 and the limit to capacity. In other words, the Buffer is cleared. The data in the Buffer is not cleared. Only the markers telling where you can write data into the Buffer are.
调用clear() position=0,limit=capacity
If there is any unread data in the Buffer when you call clear() that data will be "forgotten", meaning you no longer have any markers telling what data has been read, and what has not been read.
If there is still unread data in the Buffer, and you want to read it later, but you need to do some writing first, call compact() instead of clear().
compact() copies all unread data to the beginning of the Buffer. Then it sets position to right after the last unread element. The limit property is still set to capacity, just like clear() does. Now the Buffer is ready for writing, but you will not overwrite the unread data.

mark() and reset()

You can mark a given position in a Buffer by calling the Buffer.mark() method. You can then later reset the position back to the marked position by calling the Buffer.reset() method. Here is an example:

buffer.mark();

//call buffer.get() a couple of times, e.g. during parsing.

buffer.reset();  //set position back to mark.  
equals() and compareTo()

It is possible to compare two buffers using equals() and compareTo().

equals()
Two buffers are equal if:

They are of the same type (byte, char, int etc.)
They have the same amount of remaining bytes, chars etc. in the buffer.
All remaining bytes, chars etc. are equal.
As you can see, equals only compares part of the Buffer, not every single element inside it. In fact, it just compares the remaining elements in the Buffer.

compareTo()
The compareTo() method compares the remaining elements (bytes, chars etc.) of the two buffers, for use in e.g. sorting routines. A buffer is considered "smaller" than another buffer if:

The first element which is equal to the corresponding element in the other buffer, is smaller than that in the other buffer.
All elements are equal, but the first buffer runs out of elements before the second buffer does (it has fewer elements).

所以Buffer类的用法:

1.申请到了Bufffer后,直接可以执行写;
2.读操作的时候,flip;
3.如果想要重新读,rewind;
4.如果读了一部分,想要继续写,compact;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,099评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,828评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,540评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,848评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,971评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,132评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,193评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,934评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,376评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,687评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,846评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,537评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,175评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,887评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,134评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,674评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,741评论 2 351