下面的这张图可以形象说明以上输出的原因。
字节的存放顺序不同的机器会以不同的字节排序方法来存储数据。有“big endian”(大端法)和“little endian”(小端法)两种。大端法将重要的字节存放在存储器的低地址位;小端法将重要字节放在存储器的高地址位。当存储量大于一个字节,比如int、float等,就需要考虑字节存储的顺序问题。
ByteBuffer是以大端法存数数据的,并且数据在网上传输也是大端法顺序。我们是可以使用ByteOrder.BIG_ENDIAN或者ByteOrder.LITTLE_ENDIAN的order()方法改变ByteBuffer的字节排序方式。
用缓冲器操作数据nio类之间的关系
上面的这张图阐明了nio之间的关系,便于我们理解怎样去移动和转换数据。例如,想要把一个字节数组写到文件中去,那么我们就应该做以下事情:
使用ByteBuffer.wrap()方法把字节数组包装起来
然后,使用getChannel()方法在FileOutputStream上打开一个通道
最后,将ByteBuffer中的数据写到FileChannel中去
我们需要注意:ByteBuffer是将数据移进移出通道的唯一方式。我们不能将基本类型缓冲器转换成ByteBuffer,但是,我们可以经由基本类型缓冲器(视图缓冲器)来操纵ByteBuffer中的数据。
缓冲器的更多方法使用
Buffer由数据和可以高效地访问及操纵这些数据的四个索引组成,这四个索引是:mark(标记)、position(位置)、limit(界限)和capacity(容量)。下面是设置索引和复位索引以及查询它们的值的方法。
方法 含义capacity() 返回缓冲区容量
clear() 清空缓冲区,将position设置为0,limit设置为容量。
flip() 将limit设置为position,position设置为0。此方法用于准备从缓冲区读取已经写入的方法
limit() 返回limit值
limit(int lim) 设置limit值
mark() 将mark设置为position
reset() 将此缓冲区的位置重置为以前标记的位置
position() 返回position值
position(int pos) 设置position值
remaining() 返回(limit-position),即缓冲区还剩余多少空间
hasRemaining() 若有介于position和limit之间的元素,则返回true
在缓冲器中插入和提取数据将会更新这些索引,用于反应所发生的变化。下面将通过一个简单的交换相邻字符来描绘这种变化过程。
public class UsingBuffers { private static void symmetricScramble(CharBuffer buffer) { while(buffer.hasRemaining()) { buffer.mark(); char c1 = buffer.get(); char c2 = buffer.get(); buffer.reset(); buffer.put(c2).put(c1); } } public static void main(String[] args) { char[] data = "UsingBuffers".toCharArray(); ByteBuffer bb = ByteBuffer.allocate(data.length * 2); CharBuffer cb = bb.asCharBuffer(); cb.put(data); System.out.println(cb.rewind()); symmetricScramble(cb); System.out.println(cb.rewind()); symmetricScramble(cb); System.out.println(cb.rewind()); } } /* output: UsingBuffers sUniBgfuefsr UsingBuffers */我们在这里采用的是分配一个底层的ByteBuffer,在其之上产生一个CharBuffer视图缓冲器来进行操作。
下面的这组图形将描绘交换相邻字符时,缓冲区内的变化情况: