我去查看read方法的底层源码:(bb:bytebuffer)
发现read方法的实现:bb.flip()、dst.put(bb) 写入缓冲区
write方法的实现: bb.put(src) |bb.flip() (bb.put(src):写入文件需要的缓冲区)
注意put()方法中参数的不同和使用flip()方法的顺序,
使用read方法,先调用flip()方法,再将数据送入缓冲区
使用write方法,将数据写到写入文件的缓冲区,在调用flip()方法使position位置变为0,然后可以继续put,继续flip()保证每次都是从0位置开始取数据,并且每一次limit都是新放入buffer中的数据的长度,确保数据不会有错误
表明read方法和write方法都是使用put来完成的,那为什么两个方法不同呢,主要在于flip()方法
public ByteBuffer put(byte x) { hb[ix(nextPutIndex())] = x; return this; } public ByteBuffer put(int i, byte x) { hb[ix(checkIndex(i))] = x; return this; } public ByteBuffer put(byte[] src, int offset, int length) { Objects.checkFromIndexSize(offset, length, src.length); int pos = position(); if (length > limit() - pos) throw new BufferOverflowException(); System.arraycopy(src, offset, hb, ix(pos), length);// final byte[] hb; // Non-null only for heap buffers 这是hb的解释:不空。堆缓冲
position(pos + length); return this; }
public byte get() { return hb[ix(nextGetIndex())]; } public byte get(int i) { return hb[ix(checkIndex(i))]; } public ByteBuffer get(byte[] dst, int offset, int length) { Objects.checkFromIndexSize(offset, length, dst.length); int pos = position(); if (length > limit() - pos) throw new BufferUnderflowException(); System.arraycopy(hb, ix(pos), dst, offset, length); position(pos + length); return this; } public ByteBuffer get(int index, byte[] dst, int offset, int length) { Objects.checkFromIndexSize(index, length, limit()); Objects.checkFromIndexSize(offset, length, dst.length); System.arraycopy(hb, ix(index), dst, offset, length); return this; }
put方法的实现: System.arraycopy(src, offset, hb, ix(pos), length);
get方法的实现: System.arraycopy(hb, ix(pos), dst, offset, length);
@HotSpotIntrinsicCandidate public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
*指定位置,到目标数组的指定位置。
*从源复制数组组件的子序列
* {@code src}引用到目标数组的数组
*由{@code dest}引用。 复制的组件数为
*等于{@code length}参数。 的组件
*位置{@code srcPos}至
*将源数组中的{@code srcPos + length-1}复制到
*位置{@code destPos}至
*分别为目的地的{@code destPos + length-1}
*数组。
总体来说就是将src数组复制到dest数组,这个就是get方法和put方法,都是将src“表示的文件”复制到dest“表示的文件”
所以put方法和get方法可以看作是同一类方法,只不过参数位置恰好相反
而write方法和read方法是用put方法实现的,但是put()方法中的参数也是正好相反,这样就能理解write和read对文件的读取了。
回过头:我们分析flip方法:
英文api:
public Buffer flip()
After a sequence of channel-read or put operations, invoke this method to prepare for a sequence of channel-write or relative get operations. For example:
buf.put(magic); // Prepend header in.read(buf); // Read data into rest of buffer buf.flip(); // Flip buffer out.write(buf); // Write header + data to channel
This method is often used in conjunction with the compact
method when transferring data from one place to another.
- Returns:
- This buffer
调用flip方法之后:
position:表示当前指针位置变为0
limit:可以理解为指针能读取buffer中的数据的最大位置的下一个位置
注意初始化limit为capacity(最大容量)
我们使用put方法会覆盖之前的数据,不管是哪个方法都是从position位置开始的,需要注意position的变化