当调用blockedOn的时候,会调用System类 然后将中断方法设置当前线程 当中断的时候,会判断是否实现了中断方法,如果实现了则调用 接着会走到
将一个通道交叉到另一个通道
映射到直接内存
读取的数据存储多个存储桶,或者不同数据块合并为一个整体
public class FileChannelImpl extends FileChannel { // Memory allocation size for mapping buffers //映射缓冲区的内存分配大小 private static final long allocationGranularity; // Used to make native read and write calls //用来本地读写回调 private final FileDispatcher nd; // File descriptor //文件描述器 private final FileDescriptor fd; // File access mode (immutable) //标记可读/可写 private final boolean writable; private final boolean readable; private final boolean append; // Required to prevent finalization of creating stream (immutable) //记录调用open的对象 private final Object parent; // The path of the referenced file // (null if the parent stream is created with a file descriptor) //文件路径 private final String path; // Thread-safe set of IDs of native threads, for signalling private final NativeThreadSet threads = new NativeThreadSet(2); // Lock for operations involving position and size //锁 private final Object positionLock = new Object(); private FileChannelImpl(FileDescriptor fd, String path, boolean readable, boolean writable, boolean append, Object parent) { //文件描述符 this.fd = fd; //可读 this.readable = readable; //是否可写 this.writable = writable; this.append = append; //传递的父对象,FileInputStream/RandomAccessFile this.parent = parent; //文件路径 this.path = path; this.nd = new FileDispatcherImpl(append); } // Used by FileInputStream.getChannel() and RandomAccessFile.getChannel() //打开一个文件管道 public static FileChannel open(FileDescriptor fd, String path, boolean readable, boolean writable, Object parent) { return new FileChannelImpl(fd, path, readable, writable, false, parent); } // Used by FileOutputStream.getChannel public static FileChannel open(FileDescriptor fd, String path, boolean readable, boolean writable, boolean append, Object parent) { return new FileChannelImpl(fd, path, readable, writable, append, parent); } //是否打开 private void ensureOpen() throws IOException { if (!isOpen()) throw new ClosedChannelException(); } // -- Standard channel operations -- //父类关闭时调用 protected void implCloseChannel() throws IOException { // Release and invalidate any locks that we still hold if (fileLockTable != null) { //释放所有文件锁 for (FileLock fl: fileLockTable.removeAll()) { synchronized (fl) { if (fl.isValid()) { nd.release(fd, fl.position(), fl.size()); ((FileLockImpl)fl).invalidate(); } } } } // signal any threads blocked on this channel //通知当前通道所有被阻塞的线程 threads.signalAndWait(); //关闭调用open的对象 if (parent != null) { // Close the fd via the parent stream's close method. The parent // will reinvoke our close method, which is defined in the // superclass AbstractInterruptibleChannel, but the isOpen logic in // that method will prevent this method from being reinvoked. // ((java.io.Closeable)parent).close(); } else { //关闭文件描述器 nd.close(fd); } } public int read(ByteBuffer dst) throws IOException { //是否打开 ensureOpen(); //是否可读 if (!readable) throw new NonReadableChannelException(); synchronized (positionLock) { int n = 0; int ti = -1; try { begin(); ti = threads.add(); //再次判断是否打开 if (!isOpen()) return 0; do { n = IOUtil.read(fd, dst, -1, nd); } while ( //IO没中断 (n == IOStatus.INTERRUPTED) && //打开状态 isOpen()); return IOStatus.normalize(n); } finally { threads.remove(ti); end(n > 0); assert IOStatus.check(n); } } } public long read(ByteBuffer[] dsts, int offset, int length) throws IOException { //上下界校验 if ((offset < 0) || (length < 0) || (offset > dsts.length - length)) throw new IndexOutOfBoundsException(); //通道打开校验 ensureOpen(); //是否可读校验 if (!readable) throw new NonReadableChannelException(); synchronized (positionLock) { long n = 0; int ti = -1; try { begin(); //将当前线程加入到线程集合中,当Channel关闭时,可以发送信号给线程,避免线程被I/O阻塞住 ti = threads.add(); if (!isOpen()) return 0; do { //fd经过nd数据写入dsts n = IOUtil.read(fd, dsts, offset, length, nd); } while ((n == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(n); } finally { //I/O完成移除线程 threads.remove(ti); end(n > 0); assert IOStatus.check(n); } } } public int write(ByteBuffer src) throws IOException { ensureOpen(); if (!writable) throw new NonWritableChannelException(); synchronized (positionLock) { int n = 0; int ti = -1; try { begin(); ti = threads.add(); if (!isOpen()) return 0; do { n = IOUtil.write(fd, src, -1, nd); } while ((n == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(n); } finally { threads.remove(ti); end(n > 0); assert IOStatus.check(n); } } } public long write(ByteBuffer[] srcs, int offset, int length) throws IOException { if ((offset < 0) || (length < 0) || (offset > srcs.length - length)) throw new IndexOutOfBoundsException(); ensureOpen(); if (!writable) throw new NonWritableChannelException(); synchronized (positionLock) { long n = 0; int ti = -1; try { begin(); ti = threads.add(); if (!isOpen()) return 0; do { n = IOUtil.write(fd, srcs, offset, length, nd); } while ((n == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(n); } finally { threads.remove(ti); end(n > 0); assert IOStatus.check(n); } } } // -- Other operations -- // 表示文件中的当前字节位置 public long position() throws IOException { ensureOpen(); synchronized (positionLock) { long p = -1; int ti = -1; try { begin(); ti = threads.add(); if (!isOpen()) return 0; do { // in append-mode then position is advanced to end before writing //在append-mode模式下,则提前结束位置,返回最后的位置 //否则返回当前位置 p = (append) ? nd.size(fd) : position0(fd, -1); } while ((p == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(p); } finally { threads.remove(ti); end(p > -1); assert IOStatus.check(p); } } } public FileChannel position(long newPosition) throws IOException { ensureOpen(); if (newPosition < 0) throw new IllegalArgumentException(); synchronized (positionLock) { long p = -1; int ti = -1; try { begin(); ti = threads.add(); if (!isOpen()) return null; do { //移动到新的位置 p = position0(fd, newPosition); } while ((p == IOStatus.INTERRUPTED) && isOpen()); return this; } finally { threads.remove(ti); end(p > -1); assert IOStatus.check(p); } } } //返回管道的文件大小 public long size() throws IOException { ensureOpen(); synchronized (positionLock) { long s = -1; int ti = -1; try { begin(); ti = threads.add(); if (!isOpen()) return -1; do { s = nd.size(fd); } while ((s == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(s); } finally { threads.remove(ti); end(s > -1); assert IOStatus.check(s); } } } //砍掉指定size之外数据 public FileChannel truncate(long newSize) throws IOException { ensureOpen(); if (newSize < 0) throw new IllegalArgumentException("Negative size"); if (!writable) throw new NonWritableChannelException(); synchronized (positionLock) { int rv = -1; //记录读取位置 long p = -1; int ti = -1; long rp = -1; try { begin(); ti = threads.add(); if (!isOpen()) return null; // get current size long size; do { size = nd.size(fd); } while ((size == IOStatus.INTERRUPTED) && isOpen()); if (!isOpen()) return null; // get current position do { p = position0(fd, -1); } while ((p == IOStatus.INTERRUPTED) && isOpen()); if (!isOpen()) return null; assert p >= 0; // truncate file if given size is less than the current size //当设置的大小<文件大小,则截取文件大小到新的大小 if (newSize < size) { do { rv = nd.truncate(fd, newSize); } while ((rv == IOStatus.INTERRUPTED) && isOpen()); if (!isOpen()) return null; } // if position is beyond new size then adjust it //也就是说最小也得设置>=postion的大小位置 if (p > newSize) p = newSize; do { //重新设置位置从p开始 rp = position0(fd, p); } while ((rp == IOStatus.INTERRUPTED) && isOpen()); return this; } finally { threads.remove(ti); end(rv > -1); assert IOStatus.check(rv); } } } public void force(boolean metaData) throws IOException { ensureOpen(); int rv = -1; int ti = -1; try { begin(); ti = threads.add(); if (!isOpen()) return; do { rv = nd.force(fd, metaData); } while ((rv == IOStatus.INTERRUPTED) && isOpen()); } finally { threads.remove(ti); end(rv > -1); assert IOStatus.check(rv); } } // Assume at first that the underlying kernel supports sendfile(); // set this to false if we find out later that it doesn't // //是否支持sendfile private static volatile boolean transferSupported = true; // Assume that the underlying kernel sendfile() will work if the target // fd is a pipe; set this to false if we find out later that it doesn't // private static volatile boolean pipeSupported = true; // Assume that the underlying kernel sendfile() will work if the target // fd is a file; set this to false if we find out later that it doesn't // private static volatile boolean fileSupported = true; private long transferToDirectlyInternal(long position, int icount, WritableByteChannel target, FileDescriptor targetFD) throws IOException { assert !nd.transferToDirectlyNeedsPositionLock() || Thread.holdsLock(positionLock); long n = -1; int ti = -1; try { begin(); ti = threads.add(); if (!isOpen()) return -1; do { //直接操作文件描述符传输 n = transferTo0(fd, position, icount, targetFD); } while ((n == IOStatus.INTERRUPTED) && isOpen()); if (n == IOStatus.UNSUPPORTED_CASE) { if (target instanceof SinkChannelImpl) pipeSupported = false; if (target instanceof FileChannelImpl) fileSupported = false; return IOStatus.UNSUPPORTED_CASE; } if (n == IOStatus.UNSUPPORTED) { // Don't bother trying again transferSupported = false; return IOStatus.UNSUPPORTED; } return IOStatus.normalize(n); } finally { threads.remove(ti); end (n > -1); } } // Maximum size to map when using a mapped buffer private static final long MAPPED_TRANSFER_SIZE = 8L*1024L*1024L; private long transferFromFileChannel(FileChannelImpl src, long position, long count) throws IOException { if (!src.readable) throw new NonReadableChannelException(); synchronized (src.positionLock) { long pos = src.position(); long max = Math.min(count, src.size() - pos); long remaining = max; long p = pos; while (remaining > 0L) { long size = Math.min(remaining, MAPPED_TRANSFER_SIZE); // ## Bug: Closing this channel will not terminate the write //创建映射缓冲区 MappedByteBuffer bb = src.map(MapMode.READ_ONLY, p, size); try { //写入映射缓冲区 long n = write(bb, position); assert n > 0; p += n; position += n; remaining -= n; } catch (IOException ioe) { // Only throw exception if no bytes have been written if (remaining == max) throw ioe; break; } finally { //释放映射缓冲区 unmap(bb); } } long nwritten = max - remaining; src.position(pos + nwritten); return nwritten; } } private static final int TRANSFER_SIZE = 8192; //常规传输需要多次内存拷贝以及在用户模式和内核模式切换。 private long transferFromArbitraryChannel(ReadableByteChannel src, long position, long count) throws IOException { // Untrusted target: Use a newly-erased buffer int c = (int)Math.min(count, TRANSFER_SIZE); //创建临时缓冲区 ByteBuffer bb = Util.getTemporaryDirectBuffer(c); long tw = 0; // Total bytes written long pos = position; try { Util.erase(bb); while (tw < count) { bb.limit((int)Math.min((count - tw), (long)TRANSFER_SIZE)); // ## Bug: Will block reading src if this channel // ## is asynchronously closed //读入临时缓冲区 int nr = src.read(bb); if (nr <= 0) break; bb.flip(); //写入目标 int nw = write(bb, pos); tw += nw; if (nw != nr) break; pos += nw; bb.clear(); } return tw; } catch (IOException x) { if (tw > 0) return tw; throw x; } finally { //释放临时缓冲区 Util.releaseTemporaryDirectBuffer(bb); } } public long transferFrom(ReadableByteChannel src, long position, long count) throws IOException { //判断通道状态 ensureOpen(); if (!src.isOpen()) throw new ClosedChannelException(); if (!writable) throw new NonWritableChannelException(); if ((position < 0) || (count < 0)) throw new IllegalArgumentException(); if (position > size()) return 0; //如果是写入当前通道的是file通道,则采用内存映射方式传输 if (src instanceof FileChannelImpl) return transferFromFileChannel((FileChannelImpl)src, position, count); //普通方式传输 return transferFromArbitraryChannel(src, position, count); } public int read(ByteBuffer dst, long position) throws IOException { if (dst == null) throw new NullPointerException(); if (position < 0) throw new IllegalArgumentException("Negative position"); if (!readable) throw new NonReadableChannelException(); ensureOpen(); if (nd.needsPositionLock()) { synchronized (positionLock) { return readInternal(dst, position); } } else { return readInternal(dst, position); } } private int readInternal(ByteBuffer dst, long position) throws IOException { assert !nd.needsPositionLock() || Thread.holdsLock(positionLock); int n = 0; int ti = -1; try { begin(); ti = threads.add(); if (!isOpen()) return -1; do { n = IOUtil.read(fd, dst, position, nd); } while ((n == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(n); } finally { threads.remove(ti); end(n > 0); assert IOStatus.check(n); } } public int write(ByteBuffer src, long position) throws IOException { if (src == null) throw new NullPointerException(); if (position < 0) throw new IllegalArgumentException("Negative position"); if (!writable) throw new NonWritableChannelException(); ensureOpen(); if (nd.needsPositionLock()) { synchronized (positionLock) { return writeInternal(src, position); } } else { return writeInternal(src, position); } } private int writeInternal(ByteBuffer src, long position) throws IOException { assert !nd.needsPositionLock() || Thread.holdsLock(positionLock); int n = 0; int ti = -1; try { begin(); ti = threads.add(); if (!isOpen()) return -1; do { n = IOUtil.write(fd, src, position, nd); } while ((n == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(n); } finally { threads.remove(ti); end(n > 0); assert IOStatus.check(n); } } // -- Memory-mapped buffers -- private static class Unmapper implements Runnable { // may be required to close file private static final NativeDispatcher nd = new FileDispatcherImpl(); // keep track of mapped buffer usage static volatile int count; static volatile long totalSize; static volatile long totalCapacity; private volatile long address; private final long size; private final int cap; private final FileDescriptor fd; private Unmapper(long address, long size, int cap, FileDescriptor fd) { assert (address != 0); this.address = address; this.size = size; this.cap = cap; this.fd = fd; synchronized (Unmapper.class) { count++; totalSize += size; totalCapacity += cap; } } public void run() { if (address == 0) return; //移除内存映射 unmap0(address, size); address = 0; // if this mapping has a valid file descriptor then we close it if (fd.valid()) { try { //关闭文件描述符 nd.close(fd); } catch (IOException ignore) { // nothing we can do } } synchronized (Unmapper.class) { count--; totalSize -= size; totalCapacity -= cap; } } } private static void unmap(MappedByteBuffer bb) { Cleaner cl = ((DirectBuffer)bb).cleaner(); if (cl != null) cl.clean(); } private static final int MAP_RO = 0; private static final int MAP_RW = 1; private static final int MAP_PV = 2; public MappedByteBuffer map(MapMode mode, long position, long size) throws IOException { //判断是否打开 ensureOpen(); //mode空判断 if (mode == null) throw new NullPointerException("Mode is null"); if (position < 0L) throw new IllegalArgumentException("Negative position"); if (size < 0L) throw new IllegalArgumentException("Negative size"); if (position + size < 0) throw new IllegalArgumentException("Position + size overflow"); if (size > Integer.MAX_VALUE) throw new IllegalArgumentException("Size exceeds Integer.MAX_VALUE"); //获取映射模式 int imode = -1; if (mode == MapMode.READ_ONLY) imode = MAP_RO; else if (mode == MapMode.READ_WRITE) imode = MAP_RW; else if (mode == MapMode.PRIVATE) imode = MAP_PV; assert (imode >= 0); //如果该文件不能写,但是模式设置可写或者private,则冲突异常 if ((mode != MapMode.READ_ONLY) && !writable) throw new NonWritableChannelException(); //文件不能读,但模式设置可读或private,则冲突异常 if (!readable) throw new NonReadableChannelException(); long addr = -1; int ti = -1; try { //调用父类 begin(); ti = threads.add(); //再次判断通道是否打开 if (!isOpen()) return null; long filesize; do { filesize = nd.size(fd); //channel打开且IO没中断 } while ((filesize == IOStatus.INTERRUPTED) && isOpen()); if (!isOpen()) return null; //当文件大小<映射的大小,则扩展文件大小 if (filesize < position + size) { // Extend file size //不能写直接异常 if (!writable) { throw new IOException("Channel not open for writing " + "- cannot extend file to required size"); } int rv; do { //扩展大小 rv = nd.truncate(fd, position + size); } while ((rv == IOStatus.INTERRUPTED) && isOpen()); //再次判断管道是否关闭 if (!isOpen()) return null; } //size=0,返回一个DirectByteBufferR if (size == 0) { addr = 0; // a valid file descriptor is not required FileDescriptor dummy = new FileDescriptor(); if ((!writable) || (imode == MAP_RO)) return Util.newMappedByteBufferR(0, 0, dummy, null); else return Util.newMappedByteBuffer(0, 0, dummy, null); } //重新计算位置,是映射缓冲区的倍数 int pagePosition = (int)(position % allocationGranularity); long mapPosition = position - pagePosition; long mapSize = size + pagePosition; try { // If no exception was thrown from map0, the address is valid //获取映射地址 addr = map0(imode, mapPosition, mapSize); } catch (OutOfMemoryError x) { // An OutOfMemoryError may indicate that we've exhausted memory // so force gc and re-attempt map //OOM,则释放内存 System.gc(); try { Thread.sleep(100); } catch (InterruptedException y) { Thread.currentThread().interrupt(); } try { //再次分配地址 addr = map0(imode, mapPosition, mapSize); } catch (OutOfMemoryError y) { // After a second OOME, fail throw new IOException("Map failed", y); } } // On Windows, and potentially other platforms, we need an open // file descriptor for some mapping operations. FileDescriptor mfd; try { //创建一个内存映射的文件描述符,指向当前的native文件描述符 mfd = nd.duplicateForMapping(fd); } catch (IOException ioe) { unmap0(addr, mapSize); throw ioe; } //校验IO状态 assert (IOStatus.checkAll(addr)); //校验地址是否allocationGranularity整数倍 assert (addr % allocationGranularity == 0); //获取低32位 int isize = (int)size; //回收器 Unmapper um = new Unmapper(addr, mapSize, isize, mfd); //不能写或者模式为只读,则创建只读Buffer,所有写操作都抛异常 if ((!writable) || (imode == MAP_RO)) { return Util.newMappedByteBufferR(isize, addr + pagePosition, mfd, um); } else { return Util.newMappedByteBuffer(isize, addr + pagePosition, mfd, um); } } finally { threads.remove(ti); end(IOStatus.checkAll(addr)); } } /** * Invoked by sun.management.ManagementFactoryHelper to create the management * interface for mapped buffers. */ public static sun.misc.JavaNioAccess.BufferPool getMappedBufferPool() { return new sun.misc.JavaNioAccess.BufferPool() { @Override public String getName() { return "mapped"; } @Override public long getCount() { return Unmapper.count; } @Override public long getTotalCapacity() { return Unmapper.totalCapacity; } @Override public long getMemoryUsed() { return Unmapper.totalSize; } }; } // -- Locks -- // keeps track of locks on this file private volatile FileLockTable fileLockTable; // indicates if file locks are maintained system-wide (as per spec) private static boolean isSharedFileLockTable; // indicates if the disableSystemWideOverlappingFileLockCheck property // has been checked private static volatile boolean propertyChecked; // The lock list in J2SE 1.4/5.0 was local to each FileChannel instance so // the overlap check wasn't system wide when there were multiple channels to // the same file. This property is used to get 1.4/5.0 behavior if desired. private static boolean isSharedFileLockTable() { if (!propertyChecked) { synchronized (FileChannelImpl.class) { if (!propertyChecked) { String value = AccessController.doPrivileged( new GetPropertyAction( "sun.nio.ch.disableSystemWideOverlappingFileLockCheck")); isSharedFileLockTable = ((value == null) || value.equals("false")); propertyChecked = true; } } } return isSharedFileLockTable; } private FileLockTable fileLockTable() throws IOException { if (fileLockTable == null) { synchronized (this) { if (fileLockTable == null) { //根据独占和共享模式,建立不同锁表 if (isSharedFileLockTable()) { int ti = threads.add(); try { ensureOpen(); fileLockTable = FileLockTable.newSharedFileLockTable(this, fd); } finally { threads.remove(ti); } } else { fileLockTable = new SimpleFileLockTable(); } } } } return fileLockTable; } public FileLock lock(long position, long size, boolean shared) throws IOException { ensureOpen(); //写模式不能共享锁 if (shared && !readable) throw new NonReadableChannelException(); //读模式不能独占锁 if (!shared && !writable) throw new NonWritableChannelException(); //新建一个锁对象 FileLockImpl fli = new FileLockImpl(this, position, size, shared); //获取文件锁表 FileLockTable flt = fileLockTable(); //添加文件锁表 flt.add(fli); //标记是否执行完毕 boolean completed = false; int ti = -1; try { begin(); ti = threads.add(); if (!isOpen()) return null; int n; do { //调用native方法加锁 n = nd.lock(fd, true, position, size, shared); } while ((n == FileDispatcher.INTERRUPTED) && isOpen()); if (isOpen()) { //部分操作系统不支持共享锁,若获取到的是独占锁,则更新当前FileLockImpl为独占锁 if (n == FileDispatcher.RET_EX_LOCK) { assert shared; FileLockImpl fli2 = new FileLockImpl(this, position, size, false); flt.replace(fli, fli2); fli = fli2; } completed = true; } } finally { //加锁失败,移除锁 if (!completed) flt.remove(fli); threads.remove(ti); try { end(completed); } catch (ClosedByInterruptException e) { throw new FileLockInterruptionException(); } } return fli; } public FileLock tryLock(long position, long size, boolean shared) throws IOException { ensureOpen(); if (shared && !readable) throw new NonReadableChannelException(); if (!shared && !writable) throw new NonWritableChannelException(); FileLockImpl fli = new FileLockImpl(this, position, size, shared); FileLockTable flt = fileLockTable(); flt.add(fli); int result; int ti = threads.add(); try { try { ensureOpen(); result = nd.lock(fd, false, position, size, shared); } catch (IOException e) { flt.remove(fli); throw e; } if (result == FileDispatcher.NO_LOCK) { flt.remove(fli); return null; } if (result == FileDispatcher.RET_EX_LOCK) { assert shared; FileLockImpl fli2 = new FileLockImpl(this, position, size, false); flt.replace(fli, fli2); return fli2; } return fli; } finally { threads.remove(ti); } } void release(FileLockImpl fli) throws IOException { int ti = threads.add(); try { ensureOpen(); //释放锁 nd.release(fd, fli.position(), fli.size()); } finally { threads.remove(ti); } assert fileLockTable != null; //从锁表中移除 fileLockTable.remove(fli); } // -- File lock support -- /** * A simple file lock table that maintains a list of FileLocks obtained by a * FileChannel. Use to get 1.4/5.0 behaviour. */ private static class SimpleFileLockTable extends FileLockTable { // synchronize on list for access private final List<FileLock> lockList = new ArrayList<FileLock>(2); public SimpleFileLockTable() { } private void checkList(long position, long size) throws OverlappingFileLockException { assert Thread.holdsLock(lockList); for (FileLock fl: lockList) { if (fl.overlaps(position, size)) { throw new OverlappingFileLockException(); } } } public void add(FileLock fl) throws OverlappingFileLockException { synchronized (lockList) { checkList(fl.position(), fl.size()); lockList.add(fl); } } public void remove(FileLock fl) { synchronized (lockList) { lockList.remove(fl); } } public List<FileLock> removeAll() { synchronized(lockList) { List<FileLock> result = new ArrayList<FileLock>(lockList); lockList.clear(); return result; } } public void replace(FileLock fl1, FileLock fl2) { synchronized (lockList) { lockList.remove(fl1); lockList.add(fl2); } } } // -- Native methods -- // Creates a new mapping private native long map0(int prot, long position, long length) throws IOException; // Removes an existing mapping private static native int unmap0(long address, long length); // Transfers from src to dst, or returns -2 if kernel can't do that private native long transferTo0(FileDescriptor src, long position, long count, FileDescriptor dst); // Sets or reports this file's position // If offset is -1, the current position is returned // otherwise the position is set to offset //返回当前文件位置,offset-1则返回当前位置 private native long position0(FileDescriptor fd, long offset); // Caches fieldIDs private static native long initIDs(); static { IOUtil.load(); allocationGranularity = initIDs(); } }private long transferToArbitraryChannel(long position, int icount, WritableByteChannel target) throws IOException { // Untrusted target: Use a newly-erased buffer //最大只能传传8192 int c = Math.min(icount, TRANSFER_SIZE); //创建固定大小缓存 ByteBuffer bb = Util.getTemporaryDirectBuffer(c); long tw = 0; // Total bytes written long pos = position; try { Util.erase(bb); while (tw < icount) { //设置可读边界 bb.limit(Math.min((int)(icount - tw), TRANSFER_SIZE)); //将数据读取到临时缓冲区 int nr = read(bb, pos); if (nr <= 0) break; bb.flip(); // ## Bug: Will block writing target if this channel // ## is asynchronously closed //数据写入目标缓冲区 int nw = target.write(bb); //重新计算读取索引 tw += nw; //说明目标写满,直接退出 if (nw != nr) break; pos += nw; //重置位置和可读个数 bb.clear(); } return tw; } catch (IOException x) { if (tw > 0) return tw; throw x; } finally { //释放缓冲区内存 Util.releaseTemporaryDirectBuffer(bb); } }