- 浏览: 980148 次
文章分类
- 全部博客 (428)
- Hadoop (2)
- HBase (1)
- ELK (1)
- ActiveMQ (13)
- Kafka (5)
- Redis (14)
- Dubbo (1)
- Memcached (5)
- Netty (56)
- Mina (34)
- NIO (51)
- JUC (53)
- Spring (13)
- Mybatis (17)
- MySQL (21)
- JDBC (12)
- C3P0 (5)
- Tomcat (13)
- SLF4J-log4j (9)
- P6Spy (4)
- Quartz (12)
- Zabbix (7)
- JAVA (9)
- Linux (15)
- HTML (9)
- Lucene (0)
- JS (2)
- WebService (1)
- Maven (4)
- Oracle&MSSQL (14)
- iText (11)
- Development Tools (8)
- UTILS (4)
- LIFE (8)
最新评论
-
Donald_Draper:
Donald_Draper 写道刘落落cici 写道能给我发一 ...
DatagramChannelImpl 解析三(多播) -
Donald_Draper:
刘落落cici 写道能给我发一份这个类的源码吗Datagram ...
DatagramChannelImpl 解析三(多播) -
lyfyouyun:
请问楼主,执行消息发送的时候,报错:Transport sch ...
ActiveMQ连接工厂、连接详解 -
ezlhq:
关于 PollArrayWrapper 状态含义猜测:参考 S ...
WindowsSelectorImpl解析一(FdMap,PollArrayWrapper) -
flyfeifei66:
打算使用xmemcache作为memcache的客户端,由于x ...
Memcached分布式客户端(Xmemcached)
Java Socket编程实例:http://donald-draper.iteye.com/blog/2356695
java Socket读写缓存区Writer和Reader:http://donald-draper.iteye.com/blog/2356885
前一篇文章中,我们讲了java Socket io的Writer和Reader,在上一篇中,在流解码器和编码器中,经常用到字节缓冲ByteBuffer,今天我们就来看一ByteBuffer。
ByteBuffer有两个实现一个为,HeapByteBuffer,另一个为DirectByteBuffer,这两个有什么区别呢?
我们引入原文,不翻译以免都是原味;
1.HeapByteBuffer
HeapByteBuffer使用的java堆内存
2.DirectByteBuffer
DirectByteBuffer使用的是:the Java virtual machine will make a best effort to
perform native I/O operations directly upon it.
使用时要注意:It is therefore recommended that direct buffers be allocated
primarily for large, long-lived buffers that are subject to the underlying
system's native I/O operations
今天我们只讲HeapByteBuffer,ByteBuffer,Buffer,我们先从测试实例来看
mark,position,limit,capacity大小关系:
-1 <= mark <= position <= limit <= capacity;
0<= position <= limit <= capacity;
测试主类:
注意 main里面方法的调用顺序不要变,第一次测试我们先注释掉testCompact方法,控制台输出:
===============init status============
position:0
limit:32
capacity:32
===============put byte============
position:1
limit:32
capacity:32
======get byte:102
===============put char============
position:3
limit:32
capacity:32
======get Char:a
===============mark============
position:3
limit:32
capacity:32
===============put int============
position:7
limit:32
capacity:32
======get int:4
===============put float============
position:11
limit:32
capacity:32
======get float:10.0
===============put double============
position:19
limit:32
capacity:32
======get double:20.0
===============put long============
position:27
limit:32
capacity:32
======get long:30
======buffer 剩余空间大小:5
java.nio.BufferOverflowException
at java.nio.Buffer.nextPutIndex(Buffer.java:519)
at java.nio.HeapByteBuffer.putLong(HeapByteBuffer.java:417)
at socket.TestByteBuffer.testOverFlow(TestByteBuffer.java:150)
at socket.TestByteBuffer.main(TestByteBuffer.java:24)
===============reset============
position:3
limit:32
capacity:32
======get int from mark:4
position:7
limit:32
capacity:32
======get int from mark after put new int value:5
===============clear============
position:0
limit:32
capacity:32
======get int after clear:5
从控制台输出可看出,ByteBuffer的put*和get*(int index)方法不改变mark,limit和capacity的值;put则回改变position的位置,put操作后position的位置为,put操作之前position+length(put 操作数);mark操作会改变mark的值,reset操作,则是将position定位到mark;clear操作并不会清空缓冲空间,而是将position复位0,limit为capacity,mark为-1;remain操作返回的是可用的空间大小为capacity-position;
如put后,超出缓冲区大小,则抛出BufferOverflowException异常。
下面我们将mark,reset和clear注释掉,测试Compact操作如下:
关注控制的compact部分输出:
===============put long============
position:27
limit:32
capacity:32
======get long:30
======buffer 剩余空间大小:5
java.nio.BufferOverflowException
at java.nio.Buffer.nextPutIndex(Buffer.java:519)
at java.nio.HeapByteBuffer.putLong(HeapByteBuffer.java:417)
at socket.TestByteBuffer.testOverFlow(TestByteBuffer.java:150)
at socket.TestByteBuffer.main(TestByteBuffer.java:24)
===============compact============
position:5
limit:32
capacity:32
======get int:4
===============flip============
===============rewind============
从控制台输出可以看出,compact操作一般在一下情况调用,
当out发送数据,即读取buf的数据,write方法可能只发送了部分数据,buf里还有剩余,
这时调用buf.compact()函数将position与limit之间的数据,copy到buf的0到limit-position,
进行压缩(非实际以压缩,只是移动),以便下次 向写入缓存。当position与limit之间的数据为空时,则不改变原缓冲区,否则copy相应数据。
//HeapByteBuffer
线面我们来看一下Buffer的相关操作:
再来看ByteBuffer
再来看
来看压缩函数
在来看一下put函数
我们,详看一下putInt
//HeapByteBuffer
//Bits
将int值x,从bb的bi位置,写入
从ByteBuffer bb的比位置获取int值
从上面可以看出向缓存中写入占多字节的原始类型Char,int,float等时,
HeapByteBuffer,通过Bit将原始类型字节拆分存入到ByteBuffer的缓存中。
总结:
get*(int index)方法不改变mark,limit和capacity的值;put则回改变position的位置,put操作后position的位置为,put操作之前position+length(put 操作数);
mark操作会改变mark的值,reset操作,则是将position定位到mark;clear操作并不会清空缓冲空间,而是将position复位0,limit为capacity,mark为-1;remain操作返回的是可用的空间大小为capacity-position;如put后,超出缓冲区大小,则抛出BufferOverflowException异常。
compact操作一般在一下情况调用,当out发送数据,即读取buf的数据,write方法可能只发送了部分数据,buf里还有剩余,这时调用buf.compact()函数将position与limit之间的数据,copy到buf的0到limit-position,进行压缩(非实际以压缩,只是移动),以便下次 向写入缓存。当position与limit之间的数据为空时,则不改变原缓冲区,否则copy相应数据。HeapByteBuffer向缓存中写入占多字节的原始类型Char,int,float等时,HeapByteBuffer,通过Bit将原始类型字节拆分存入到ByteBuffer的缓存中。
下面用图来模仿相关操作:
初始化:
写数据:
mark:
再次写数据:
reset操作:
flip操作,左图为操作前,右图为操作后;
rewind操作,左图为操作前,右图为操作后;
clear操作,上图为操作前,下图为操作后;
compact操作,有数据的情况下,上图为操作前,下图为操作后;
compact操作,无数据的情况下,上图为操作前,下图为操作后;
java Socket读写缓存区Writer和Reader:http://donald-draper.iteye.com/blog/2356885
前一篇文章中,我们讲了java Socket io的Writer和Reader,在上一篇中,在流解码器和编码器中,经常用到字节缓冲ByteBuffer,今天我们就来看一ByteBuffer。
ByteBuffer有两个实现一个为,HeapByteBuffer,另一个为DirectByteBuffer,这两个有什么区别呢?
我们引入原文,不翻译以免都是原味;
1.HeapByteBuffer
//ByteBuffer,创建方法 public static ByteBuffer allocate(int capacity) { if (capacity < 0) throw new IllegalArgumentException(); return new HeapByteBuffer(capacity, capacity); }
HeapByteBuffer使用的java堆内存
2.DirectByteBuffer
//ByteBuffer,创建方法 public static ByteBuffer allocateDirect(int capacity) { return new DirectByteBuffer(capacity); } * <p> A byte buffer is either <i>direct</i> or <i>non-direct</i>. Given a * direct byte buffer, the Java virtual machine will make a best effort to * perform native I/O operations directly upon it. That is, it will attempt to * avoid copying the buffer's content to (or from) an intermediate buffer * before (or after) each invocation of one of the underlying operating * system's native I/O operations. * * <p> A direct byte buffer may be created by invoking the {@link * #allocateDirect(int) allocateDirect} factory method of this class. The * buffers returned by this method typically have somewhat higher allocation * and deallocation costs than non-direct buffers. The contents of direct * buffers may reside outside of the normal garbage-collected heap, and so * their impact upon the memory footprint of an application might not be * obvious. It is therefore recommended that direct buffers be allocated * primarily for large, long-lived buffers that are subject to the underlying * system's native I/O operations. In general it is best to allocate direct * buffers only when they yield a measureable gain in program performance. * * <p> A direct byte buffer may also be created by {@link * java.nio.channels.FileChannel#map </code>mapping<code>} a region of a file * directly into memory. An implementation of the Java platform may optionally * support the creation of direct byte buffers from native code via JNI. If an * instance of one of these kinds of buffers refers to an inaccessible region * of memory then an attempt to access that region will not change the buffer's * content and will cause an unspecified exception to be thrown either at the * time of the access or at some later time.
DirectByteBuffer使用的是:the Java virtual machine will make a best effort to
perform native I/O operations directly upon it.
使用时要注意:It is therefore recommended that direct buffers be allocated
primarily for large, long-lived buffers that are subject to the underlying
system's native I/O operations
今天我们只讲HeapByteBuffer,ByteBuffer,Buffer,我们先从测试实例来看
public abstract class Buffer { // Invariants: mark <= position <= limit <= capacity private int mark = -1;//标记,用于reset函数,是复位position到mark位置 private int position = 0;//Buffer缓冲区读写位置 private int limit;//读写上限 private int capacity;//缓冲区容量 }
mark,position,limit,capacity大小关系:
-1 <= mark <= position <= limit <= capacity;
0<= position <= limit <= capacity;
测试主类:
package socket; import java.nio.BufferOverflowException; import java.nio.ByteBuffer; /** * 测试ByteBuffer * @author donald * 2017年2月14日 * 下午5:23:32 */ public class TestByteBuffer { private static ByteBuffer byteBuffer = null; public static void main(String[] args) { /* 以下顺序不要改变*/ initByteBuffer(); testByte(); testChar(); testMark(); testInt(); testFloat(); testDouble(); testLong(); testRemaining(); testOverFlow(); testReset(); testClear(); // testCompact(); } /** * 初始化缓存空间 */ public static void initByteBuffer(){ byteBuffer = ByteBuffer.allocate(32); System.out.println("===============init status============"); System.out.println("position:"+byteBuffer.position()); System.out.println("limit:"+byteBuffer.limit()); System.out.println("capacity:"+byteBuffer.capacity()); } /** * 测试Byte,占用一个字节 */ public static void testByte(){ System.out.println("===============put byte============"); //字节 byte bbyte = 102; byteBuffer.put(bbyte);//ByteBuffer byteBuffer.get(0);//byte System.out.println("position:"+byteBuffer.position()); System.out.println("limit:"+byteBuffer.limit()); System.out.println("capacity:"+byteBuffer.capacity()); System.out.println("======get byte:"+byteBuffer.get(0)); } /** * 测试Char,占用2个字节 */ public static void testChar(){ System.out.println("===============put char============"); //字符 char aChar= 'a'; byteBuffer.putChar(aChar); System.out.println("position:"+byteBuffer.position()); System.out.println("limit:"+byteBuffer.limit()); System.out.println("capacity:"+byteBuffer.capacity()); System.out.println("======get Char:"+byteBuffer.getChar(1)); } /** * 标记位置,以便reset,返回这个标记位置 */ public static void testMark(){ //标记位置 byteBuffer.mark(); System.out.println("===============mark============"); System.out.println("position:"+byteBuffer.position()); System.out.println("limit:"+byteBuffer.limit()); System.out.println("capacity:"+byteBuffer.capacity()); } /** * 测试int,占用4个字节 */ public static void testInt(){ System.out.println("===============put int============"); //int int int4 = 4; byteBuffer.putInt(int4); System.out.println("position:"+byteBuffer.position()); System.out.println("limit:"+byteBuffer.limit()); System.out.println("capacity:"+byteBuffer.capacity()); //这里为什么从第三个字节开始读取,因为前面一个字节和一个字符总共三个字节 System.out.println("======get int:"+byteBuffer.getInt(3)); } /** * 测试float,占用4个字节 */ public static void testFloat(){ System.out.println("===============put float============"); //float float float5 = 10; byteBuffer.putFloat(float5); System.out.println("position:"+byteBuffer.position()); System.out.println("limit:"+byteBuffer.limit()); System.out.println("capacity:"+byteBuffer.capacity()); //这里为什么从第7个字节开始读取,因为前面一个字节和一个字符,一个int总共7个字节 System.out.println("======get float:"+byteBuffer.getFloat(7)); } /** * 测试double,占用8个字节 */ public static void testDouble(){ System.out.println("===============put double============"); //double double double6 = 20.0; byteBuffer.putDouble(double6); System.out.println("position:"+byteBuffer.position()); System.out.println("limit:"+byteBuffer.limit()); System.out.println("capacity:"+byteBuffer.capacity()); //这里为什么从第11个字节开始读取,因为前面一个字节和一个字符,一个int,一个float总共11个字节 System.out.println("======get double:"+byteBuffer.getDouble(11)); } /** * 测试Long,占用8个字节 */ public static void testLong(){ System.out.println("===============put long============"); //long long long7 = (long) 30.0; byteBuffer.putLong(long7); System.out.println("position:"+byteBuffer.position()); System.out.println("limit:"+byteBuffer.limit()); System.out.println("capacity:"+byteBuffer.capacity()); //这里为什么从第19个字节开始读取,因为前面一个字节和一个字符,一个int,一个float,一个double总共19个字节 System.out.println("======get long:"+byteBuffer.getLong(19)); } /** * 测试字节缓冲的剩余空间函数 */ public static void testRemaining(){ System.out.println("======buffer 剩余空间大小:"+byteBuffer.remaining()); } /** * 测试添加元素字节长度,大于剩余空间时的情况 */ public static void testOverFlow(){ /*Exception in thread "main" java.nio.BufferOverflowException at java.nio.Buffer.nextPutIndex(Buffer.java:519) at java.nio.HeapByteBuffer.putLong(HeapByteBuffer.java:417) at socket.TestByteBuffer.main(TestByteBuffer.java:60) 超出空间,则抛出BufferOverflowException异常 */ try{ byteBuffer.putLong((long)30.0); } catch(BufferOverflowException e){ e.printStackTrace(); } } /** * 测试回到标记,position为标记的mark */ public static void testReset(){ System.out.println("===============reset============"); //回到mark标记位置,position为标记的mark byteBuffer.reset(); System.out.println("position:"+byteBuffer.position()); System.out.println("limit:"+byteBuffer.limit()); System.out.println("capacity:"+byteBuffer.capacity()); System.out.println("======get int from mark:"+byteBuffer.getInt(3)); //重新,从标记位置put一个int值,原来的内容被覆盖掉 int int5 = 5; byteBuffer.putInt(int5); System.out.println("position:"+byteBuffer.position()); System.out.println("limit:"+byteBuffer.limit()); System.out.println("capacity:"+byteBuffer.capacity()); System.out.println("======get int from mark after put new int value:"+byteBuffer.getInt(3)); } /** * clear重置position,mark,limit位置,原始缓存区内容并不清掉 */ public static void testClear(){ System.out.println("===============clear============"); //clear重置position,mark,limit位置,原始缓存区内容并不清掉 byteBuffer.clear(); System.out.println("position:"+byteBuffer.position()); System.out.println("limit:"+byteBuffer.limit()); System.out.println("capacity:"+byteBuffer.capacity()); System.out.println("======get int after clear:"+byteBuffer.getInt(3)); } public static void testCompact(){ System.out.println("===============compact============"); /* * compact操作用于当 * while (in.read(buf) >= 0 || buf.position != 0) { * buf.flip(); * out.write(buf); * buf.compact(); // In case of partial write * } * 当out发送数据,即读取buf的数据,write方法可能只发送了部分数据,buf里还有剩余, * 这时调用buf.compact()函数将position与limit之间的数据,copy到buf的0到limit-position,进行压缩(非实际以压缩,只是移动), * 以便下次 向写入缓存。 */ byteBuffer.compact(); System.out.println("position:"+byteBuffer.position()); System.out.println("limit:"+byteBuffer.limit()); System.out.println("capacity:"+byteBuffer.capacity()); System.out.println("======get int:"+byteBuffer.getInt(3)); System.out.println("===============flip============"); /* * buf.put(magic); // Prepend header * in.read(buf); // Read data into rest of buffer * buf.flip(); // Flip buffer * out.write(buf); * 当in从缓冲中读取数据后,如果想要将缓存中的数据发送出去,则调用buf.flip()函数,limit为当前position,position为0, * / // byteBuffer.flip(); System.out.println("===============rewind============"); /* * out.write(buf); // Write remaining data * buf.rewind(); // Rewind buffer * buf.get(array); // Copy data into array</pre></blockquote> * 当out写出数据,即读取buf的数据后,如果想要从缓存中,从0位置,获取缓存数据,则调用buf.rewind() */ // byteBuffer.rewind(); } }
注意 main里面方法的调用顺序不要变,第一次测试我们先注释掉testCompact方法,控制台输出:
===============init status============
position:0
limit:32
capacity:32
===============put byte============
position:1
limit:32
capacity:32
======get byte:102
===============put char============
position:3
limit:32
capacity:32
======get Char:a
===============mark============
position:3
limit:32
capacity:32
===============put int============
position:7
limit:32
capacity:32
======get int:4
===============put float============
position:11
limit:32
capacity:32
======get float:10.0
===============put double============
position:19
limit:32
capacity:32
======get double:20.0
===============put long============
position:27
limit:32
capacity:32
======get long:30
======buffer 剩余空间大小:5
java.nio.BufferOverflowException
at java.nio.Buffer.nextPutIndex(Buffer.java:519)
at java.nio.HeapByteBuffer.putLong(HeapByteBuffer.java:417)
at socket.TestByteBuffer.testOverFlow(TestByteBuffer.java:150)
at socket.TestByteBuffer.main(TestByteBuffer.java:24)
===============reset============
position:3
limit:32
capacity:32
======get int from mark:4
position:7
limit:32
capacity:32
======get int from mark after put new int value:5
===============clear============
position:0
limit:32
capacity:32
======get int after clear:5
从控制台输出可看出,ByteBuffer的put*和get*(int index)方法不改变mark,limit和capacity的值;put则回改变position的位置,put操作后position的位置为,put操作之前position+length(put 操作数);mark操作会改变mark的值,reset操作,则是将position定位到mark;clear操作并不会清空缓冲空间,而是将position复位0,limit为capacity,mark为-1;remain操作返回的是可用的空间大小为capacity-position;
如put后,超出缓冲区大小,则抛出BufferOverflowException异常。
下面我们将mark,reset和clear注释掉,测试Compact操作如下:
public static void main(String[] args) { /* 以下顺序不要改变*/ initByteBuffer(); testByte(); testChar(); // testMark(); testInt(); testFloat(); testDouble(); testLong(); testRemaining(); testOverFlow(); // testReset(); // testClear(); testCompact(); }
关注控制的compact部分输出:
===============put long============
position:27
limit:32
capacity:32
======get long:30
======buffer 剩余空间大小:5
java.nio.BufferOverflowException
at java.nio.Buffer.nextPutIndex(Buffer.java:519)
at java.nio.HeapByteBuffer.putLong(HeapByteBuffer.java:417)
at socket.TestByteBuffer.testOverFlow(TestByteBuffer.java:150)
at socket.TestByteBuffer.main(TestByteBuffer.java:24)
===============compact============
position:5
limit:32
capacity:32
======get int:4
===============flip============
===============rewind============
从控制台输出可以看出,compact操作一般在一下情况调用,
/* * compact操作用于当 * while (in.read(buf) >= 0 || buf.position != 0) { * buf.flip(); * out.write(buf); * buf.compact(); // In case of partial write * } */
当out发送数据,即读取buf的数据,write方法可能只发送了部分数据,buf里还有剩余,
这时调用buf.compact()函数将position与limit之间的数据,copy到buf的0到limit-position,
进行压缩(非实际以压缩,只是移动),以便下次 向写入缓存。当position与limit之间的数据为空时,则不改变原缓冲区,否则copy相应数据。
//HeapByteBuffer
public ByteBuffer compact() { System.arraycopy(hb, ix(position()), hb, ix(0), remaining()); position(remaining()); limit(capacity()); discardMark(); return this; }
/* If <code>src</code> is <code>null</code>, then a * <code>NullPointerException</code> is thrown and the destination * array is not modified. */ //System public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
线面我们来看一下Buffer的相关操作:
public abstract class Buffer { // Invariants: mark <= position <= limit <= capacity private int mark = -1; private int position = 0; private int limit; private int capacity; //返回position public final int position() { return position; } //返回capacity public final int capacity() { return capacity; } //重新定义position位置,如mark位置大于新position,则废弃mark位置 public final Buffer position(int newPosition) { if ((newPosition > limit) || (newPosition < 0)) throw new IllegalArgumentException(); position = newPosition; if (mark > position) mark = -1; return this; } //返回limit public final int limit() { return limit; } //标记位置 public final Buffer mark() { mark = position; return this; } //复位position到mark位置 public final Buffer reset() { int m = mark; if (m < 0) throw new InvalidMarkException(); position = m; return this; } //clear操作并不会清空缓冲空间,而是将 //position复位0,limit为capacity,mark为-1; public final Buffer clear() { position = 0; limit = capacity; mark = -1; return this; } /* * buf.put(magic); // Prepend header * in.read(buf); // Read data into rest of buffer * buf.flip(); // Flip buffer * out.write(buf); * 当in从缓冲中读取数据后,如果想要将缓存中的数据发送出去, * 则调用buf.flip()函数,limit为当前position,position为0, */ public final Buffer flip() { limit = position; position = 0; mark = -1; return this; } /* * out.write(buf); // Write remaining data * buf.rewind(); // Rewind buffer * buf.get(array); // Copy data into array</pre></blockquote> * 当out写出数据,即读取buf的数据后,如果想要从缓存中,从0位置,获取缓存数据,则调用buf.rewind() */ public final Buffer rewind() { position = 0; mark = -1; return this; } //返回可用空间 public final int remaining() { return limit - position; } //废弃标记位置 final void discardMark() { // package-private mark = -1; } Buffer(int mark, int pos, int lim, int cap) { // package-private if (cap < 0) throw new IllegalArgumentException("Negative capacity: " + cap); this.capacity = cap; limit(lim); position(pos); if (mark >= 0) { if (mark > pos) throw new IllegalArgumentException("mark > position: (" + mark + " > " + pos + ")"); this.mark = mark; } } }
再来看ByteBuffer
public abstract class ByteBuffer extends Buffer implements Comparable<ByteBuffer> { // These fields are declared here rather than in Heap-X-Buffer in order to // reduce the number of virtual method invocations needed to access these // values, which is especially costly when coding small buffers. // final byte[] hb; // Non-null only for heap buffers,缓存空间 final int offset; boolean isReadOnly; ByteBuffer(int mark, int pos, int lim, int cap, // package-private byte[] hb, int offset) { super(mark, pos, lim, cap); this.hb = hb; this.offset = offset; } }
再来看
class HeapByteBuffer extends ByteBuffer { HeapByteBuffer(byte[] buf, int off, int len) { // package-private super(-1, off, off + len, buf.length, buf, 0); /* hb = buf; offset = 0; */ } }
来看压缩函数
/* * compact操作用于当 * while (in.read(buf) >= 0 || buf.position != 0) { * buf.flip(); * out.write(buf); * buf.compact(); // In case of partial write * } * 当out发送数据,即读取buf的数据,write方法可能只发送了部分数据,buf里还有剩余, * 这时调用buf.compact()函数将position与limit之间的数据,copy到buf的0到limit-position, * 进行压缩(非实际以压缩,只是移动), * 以便下次 向写入缓存。 */ public ByteBuffer compact() { //将position与limit之间的数据,copy到buf的0到limit-position System.arraycopy(hb, ix(position()), hb, ix(0), remaining()); //重新定位position position(remaining()); //重新赋值limit limit(capacity()); //废弃标记位置 discardMark(); return this; }
在来看一下put函数
public ByteBuffer putChar(char x) { //Char,占两字节 Bits.putChar(this, ix(nextPutIndex(2)), x, bigEndian); return this; } public ByteBuffer putInt(int x) { //int占4个字节 Bits.putInt(this, ix(nextPutIndex(4)), x, bigEndian); return this; }
我们,详看一下putInt
//Buffer //判断是否有足够空间存放nb个字节,并返回position的原先位置,同时移动position final int nextPutIndex(int nb) { // package-private if (limit - position < nb) throw new BufferOverflowException(); int p = position; position += nb; return p; }
//HeapByteBuffer
//定位到缓存写开始的位置 protected int ix(int i) { return i + offset; }
//Bits
将int值x,从bb的bi位置,写入
static void putInt(ByteBuffer bb, int bi, int x, boolean bigEndian) { if (bigEndian) putIntB(bb, bi, x); else putIntL(bb, bi, x); } //由于int占4个字节,将int的每个字节,拆分放入缓存ByteBuffer中 static void putIntL(ByteBuffer bb, int bi, int x) { bb._put(bi + 3, int3(x)); bb._put(bi + 2, int2(x)); bb._put(bi + 1, int1(x)); bb._put(bi , int0(x)); } private static byte int3(int x) { return (byte)(x >> 24); } private static byte int2(int x) { return (byte)(x >> 16); } private static byte int1(int x) { return (byte)(x >> 8); } private static byte int0(int x) { return (byte)(x ); }
从ByteBuffer bb的比位置获取int值
static int getIntL(ByteBuffer bb, int bi) { return makeInt(bb._get(bi + 3), bb._get(bi + 2), bb._get(bi + 1), bb._get(bi )); static private int makeInt(byte b3, byte b2, byte b1, byte b0) { return (((b3 ) << 24) | ((b2 & 0xff) << 16) | ((b1 & 0xff) << 8) | ((b0 & 0xff) )); }
从上面可以看出向缓存中写入占多字节的原始类型Char,int,float等时,
HeapByteBuffer,通过Bit将原始类型字节拆分存入到ByteBuffer的缓存中。
总结:
get*(int index)方法不改变mark,limit和capacity的值;put则回改变position的位置,put操作后position的位置为,put操作之前position+length(put 操作数);
mark操作会改变mark的值,reset操作,则是将position定位到mark;clear操作并不会清空缓冲空间,而是将position复位0,limit为capacity,mark为-1;remain操作返回的是可用的空间大小为capacity-position;如put后,超出缓冲区大小,则抛出BufferOverflowException异常。
compact操作一般在一下情况调用,当out发送数据,即读取buf的数据,write方法可能只发送了部分数据,buf里还有剩余,这时调用buf.compact()函数将position与limit之间的数据,copy到buf的0到limit-position,进行压缩(非实际以压缩,只是移动),以便下次 向写入缓存。当position与limit之间的数据为空时,则不改变原缓冲区,否则copy相应数据。HeapByteBuffer向缓存中写入占多字节的原始类型Char,int,float等时,HeapByteBuffer,通过Bit将原始类型字节拆分存入到ByteBuffer的缓存中。
下面用图来模仿相关操作:
初始化:
写数据:
mark:
再次写数据:
reset操作:
flip操作,左图为操作前,右图为操作后;
rewind操作,左图为操作前,右图为操作后;
clear操作,上图为操作前,下图为操作后;
compact操作,有数据的情况下,上图为操作前,下图为操作后;
compact操作,无数据的情况下,上图为操作前,下图为操作后;
发表评论
-
文件通道解析二(文件锁,关闭通道)
2017-05-16 23:17 1065文件通道解析一(读写操作,通道数据传输等):http://do ... -
文件通道解析一(读写操作,通道数据传输等)
2017-05-16 10:04 1164Reference定义(PhantomRefere ... -
文件通道创建方式综述
2017-05-15 17:39 1066Reference定义(PhantomReference,Cl ... -
文件读写方式简单综述后续(文件,流构造)
2017-05-14 23:04 1480Java Socket通信实例:http://donald-d ... -
文件读写方式简单综述
2017-05-14 11:13 1135Java Socket通信实例:http://donald-d ... -
FileChanne定义
2017-05-12 23:28 936文件读写方式简单综述:http://donald-draper ... -
SeekableByteChannel接口定义
2017-05-11 08:43 1235ByteChannel,分散聚集通道接口的定义(SocketC ... -
FileChannel示例
2017-05-11 08:37 992前面我们看过socket通道,datagram通道,以管道Pi ... -
PipeImpl解析
2017-05-11 08:41 932ServerSocketChannel定义:http://do ... -
Pipe定义
2017-05-10 09:07 904Channel接口定义:http://donald-drape ... -
NIO-Pipe示例
2017-05-10 08:47 905PipeImpl解析:http://donald-draper ... -
DatagramChannelImpl 解析四(地址绑定,关闭通道等)
2017-05-10 08:27 776DatagramChannelImpl 解析一(初始化):ht ... -
DatagramChannelImpl 解析三(多播)
2017-05-10 08:20 1893DatagramChannelImpl 解析一(初始化):ht ... -
NIO-UDP实例
2017-05-09 12:32 1585DatagramChannelImpl 解析一(初始化):ht ... -
DatagramChannelImpl 解析二(报文发送与接收)
2017-05-09 09:03 1405DatagramChannelImpl 解析一(初始化):ht ... -
DatagramChannelImpl 解析一(初始化)
2017-05-08 21:52 1407Channel接口定义:http://donald-drape ... -
MembershipKeyImpl 简介
2017-05-08 09:11 923MembershipKey定义:http://donald-d ... -
DatagramChannel定义
2017-05-07 23:13 1228Channel接口定义:http://donald-drape ... -
MulticastChanne接口定义
2017-05-07 13:45 1136NetworkChannel接口定义:ht ... -
MembershipKey定义
2017-05-06 16:20 916package java.nio.channels; i ...
相关推荐
Java NIO(New IO)是Java 1.4版本引入的一个新模块,全称为Non-blocking Input/Output,它提供了一种不同于传统IO的编程模型,传统IO基于块I/O(Blocking I/O),而NIO则基于通道(Channels)和缓冲区(Buffers)...
1. `java.nio`:这个包定义了Buffer及其子类,例如ByteBuffer,CharBuffer等。Buffer是NIO的核心组件,它是一个可以存储特定类型数据(如字节、字符、整数等)的线性容器。每个Buffer有capacity(容量)、limit...
### Java NIO 实现Socket通信详解 #### 一、NIO与传统IO的区别及优势 在探讨如何使用Java NIO实现Socket通信之前,我们需要先理解NIO(Non-blocking I/O,非阻塞I/O)与传统阻塞I/O之间的区别。 **传统阻塞I/O...
### Java NIO与ByteBuffer详解 #### 一、Java NIO简介 Java NIO(New I/O)是Java SE 1.4版本引入的一种新的I/O处理方式,它提供了与传统BIO(Blocking I/O)不同的数据处理机制。NIO的核心组件包括`Channels`、`...
### Java NIO 系列教程(一):Java NIO 概述 #### 一、引言 Java NIO(New IO)是Java SE 1.4版本引入的一个新的I/O处理框架,它提供了比传统Java IO包更高效的数据处理方式。NIO的核心在于其三大组件:Channels...
### Java NIO 原理与使用详解 #### 一、Java NIO 概述 在深入了解 Java NIO 的工作原理及其使用之前,我们首先来了解一下什么是 Java NIO(New I/O)。Java NIO 是 Java SE 1.4 版本引入的一个全新的 I/O API,...
### Java NIO 系列教程知识点详解 #### Java NIO 概述 Java NIO (New IO) 是从 Java 1.4 开始提供的一种新的 I/O 处理方式,旨在改进传统 Java IO API 的性能并引入更高效的数据处理机制。Java NIO 主要包括三大...
### Java NIO 相关知识点详解 #### Java NIO 概述 Java NIO(New IO)是从 Java 1.4 版本开始引入的一种新的 I/O 处理方式,它提供了一种不同于传统 Java IO 的操作模式。NIO 的核心组件包括 Channel(通道)、...
Java NIO实战之聊天室功能详解 Java NIO实战之聊天室功能详解主要介绍了Java NIO实战之聊天室功能,结合实例形式详细分析了Java NIO聊天室具体的服务端、客户端相关实现方法与操作注意事项。 Java NIO概述 Java ...
### Java NIO_API详解:构建高性能I/O操作的基石 #### 概述 在Java的早期版本中,I/O操作主要依赖于`java.io`包提供的流式、同步的API,这种模型对于多数应用场景而言已经足够高效且易于使用。然而,随着对性能...
### Java NIO 教程知识点详解 #### 一、Java NIO 概述 Java NIO(New IO),从 Java 1.4 开始引入,是 Java 标准 IO API 的一个补充,提供了与标准 IO 不同的工作方式。Java NIO 的主要特性包括: 1. **基于通道...
### Java NIO API详解 #### 一、引言 在Java早期版本中,I/O操作主要依赖于`java.io`包中的流式API,这些API虽然简单易用,但其本质是阻塞式的,这意味着每次读写操作都会等待直至完成。这种机制在处理大量并发...
ByteBuffer是Java NIO(Non-Blocking I/O)的一部分,允许开发者高效地读写大量原始字节,如处理图像、音频或网络数据。本文将深入探讨Android中ByteBuffer的工作原理及其常见应用场景。 一、ByteBuffer的基础概念 ...
### Java NIO 详解 #### 一、基本概念 在深入了解Java NIO(New IO)之前,我们需要先明确几个基础概念: - **IO (Input/Output)**:输入输出操作是计算机系统与外部设备(如硬盘、键盘、网络等)之间交换数据的...
### Java NIO 核心概念详解 #### 一、Java NIO 基本介绍 Java NIO(New IO 或 NonBlocking IO)是 Java 1.4 版本开始引入的一种全新的 I/O API,旨在提高 I/O 吞吐量。与传统的阻塞 I/O 相比,NIO 的设计思想更为...
《Java NIO详解》 Java NIO(Non-Blocking Input/Output)是Java在1.4版本引入的新I/O模型,是对传统BIO(Blocking I/O)模型的一种扩展和优化。NIO的主要特点是其非阻塞特性,允许程序在等待数据准备就绪时进行...
### Java NIO (New IO) 详解 #### 1. 引言 在Java的世界里,I/O(Input/Output)操作是程序与外部环境进行交互的重要方式之一。随着技术的发展,传统I/O模型逐渐显露出一些局限性,特别是在处理高并发场景下,其...