Loading... # NIO中FileChannel如何读取数据 传统IO读取数据的字节是放在byte数组中的,而NIO引入了ByteBuffer的概念,它相当于一个缓冲区,用以替代传统的byte数组。它有两种实现方式,一种是HeapByteBuffer,另一种是DirectByteBuffer。其中HeapByteBuffer底层维护的依然是一个byte数组,也就是说,读取到的数据也会被复制到堆内存中,而DirectByteBuffer是通过Unsafe类操作直接内存,不会复制到堆内存中。 FileChannel通过IOUtil进行读写操作 ``` static int read(FileDescriptor var0, ByteBuffer var1, long var2, NativeDispatcher var4) throws IOException { if (var1.isReadOnly()) { throw new IllegalArgumentException("Read-only buffer"); } else if (var1 instanceof DirectBuffer) { return readIntoNativeBuffer(var0, var1, var2, var4); } else { ByteBuffer var5 = Util.getTemporaryDirectBuffer(var1.remaining()); int var7; try { int var6 = readIntoNativeBuffer(var0, var5, var2, var4); var5.flip(); if (var6 > 0) { var1.put(var5); } var7 = var6; } finally { Util.offerFirstTemporaryDirectBuffer(var5); } return var7; } } ``` 先判断传入的ByteBuffer是不是只读的,如果是就直接抛出异常。 再判断传入的ByteBuffer是不是DirectBuffer,如果是,就直接读取直接内存缓冲区的数据放入ByteBuffer中,如果不是,会执行`ByteBuffer var5 = Util.getTemporaryDirectBuffer(var1.remaining());` ``` public class Util { private static ThreadLocal<Util.BufferCache> bufferCache; public static ByteBuffer getTemporaryDirectBuffer(int var0) { if (isBufferTooLarge(var0)) { return ByteBuffer.allocateDirect(var0); } else { // FOUCS ON THIS LINE Util.BufferCache var1 = (Util.BufferCache)bufferCache.get(); ByteBuffer var2 = var1.get(var0); if (var2 != null) { return var2; } else { if (!var1.isEmpty()) { var2 = var1.removeFirst(); free(var2); } return ByteBuffer.allocateDirect(var0); } } } } ``` 可以发现,该方法会根据传入的ByteBuffer的大小,返回一个同样大小的DirctBuffer,如果传入的ByteBuffer过大,就直接分配一个新的DirectBuffer返回,否则,就通过bufferCache获取,这是绑定在ThreadLocal中的,也就是说,使用HeapByteBuffer读写会申请一块儿与线程绑定的DirctBuffer。 拿到DirectBuffer后,依然会通过DirectBuffer去直接内存缓冲区去读取数据,区别是,读取之后,会调用`flip();`方法给limit、position、mark赋值。 ``` public Buffer flip() { limit = position; position = 0; mark = -1; return this; } ``` - capacity: 容量,也就是ByteBuffer总共可以装多少数据 - limit: 临界点,最多可读取多少数据(ByteBuffer不一定会装满) - position: 下一次读取数据的位置 - mark: 标记,在某个位置做标记,下次可以从该位置重复读取 有如下关系: mark <= position <= limit <= capacity `flip();`方法相当于初始化了DirectBuffer的读取,然后将该DirectBuffer放入var1,也就是传入的HeapByteBuffer中,其底层维护的是byte数组,相当于放入了堆内存中,也就是说无论哪种ByteBuffer,都是调用`readIntoNativeBuffer()`方法,从直接内存缓冲区中读取数据的。 Last modification:June 3rd, 2020 at 04:46 pm © 允许规范转载
看的我热血沸腾啊www.jiwenlaw.com