FileChannel中的read

在用到FileChannel读文件的时候,里面有个read方法,参数分别为:

/**
     * Reads a sequence of bytes from this channel into a subsequence of the
     * given buffers.
     *
     * <p> Bytes are read starting at this channel's current file position, and
     * then the file position is updated with the number of bytes actually
     * read.  Otherwise this method behaves exactly as specified in the {@link
     * ScatteringByteChannel} interface.  </p>
     */
    public abstract long read(ByteBuffer[] dsts, int offset, int length)
        throws IOException;

这个方法也很正常,和Io流中的read方法也差不多,只不过是把byte数组换成了ByteBuffer数组。考虑到ByteBuffer的开销很大,每次开的内存也不是byte可以比的,所以我打算省着点儿用,由于文件只有48KB,所以我就开了一个1024的ByteBuffer:

ByteBuffer[] dsts = new ByteBuffer[1];
		
		dsts[0]=ByteBuffer.allocate(1024);
		
		/**File:48,563Byte*/
		@SuppressWarnings("resource")
		FileChannel fc = new FileInputStream(new File(PATH)).getChannel();
		
		/**offset>=0 length>0 dsts.length-length=1-1024<offset*/
		fc.read(dsts, 0, 1024);
		
		fc.close();

结果一运行,报错了:

Exception in thread "main" java.lang.IndexOutOfBoundsException
	at sun.nio.ch.FileChannelImpl.read(Unknown Source)
	at com.a2.desktop.example8.bytebuff.TestByteBuffer.main(TestByteBuffer.java:23)

找到FileChannelImpl.java文件,找到这个方法:

154       public long read(ByteBuffer[] dsts, int offset, int length)
  155           throws IOException
  156       {
  157           if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
  158               throw new IndexOutOfBoundsException();
  159           ensureOpen();
  160           if (!readable)
  161               throw new NonReadableChannelException();
  162           synchronized (positionLock) {
  163               long n = 0;
  164               int ti = -1;
  165               try {
  166                   begin();
  167                   ti = threads.add();
  168                   if (!isOpen())
  169                       return 0;
  170                   do {
  171                       n = IOUtil.read(fd, dsts, offset, length, nd);
  172                   } while ((n == IOStatus.INTERRUPTED) && isOpen());
  173                   return IOStatus.normalize(n);
  174               } finally {
  175                   threads.remove(ti);
  176                   end(n > 0);
  177                   assert IOStatus.check(n);
  178               }
  179           }
  180       }

原来还需要满足offset > dsts.length – length。最近比较忙,没有时间去看底层的实现,但是这样做也合乎情理,最后附上sun实现后的FileChannel:

1   /*
    2    * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   26   package sun.nio.ch;
   27   
   28   import java.io.FileDescriptor;
   29   import java.io.IOException;
   30   import java.nio.ByteBuffer;
   31   import java.nio.MappedByteBuffer;
   32   import java.nio.channels;
   33   import java.util.ArrayList;
   34   import java.util.List;
   35   import java.security.AccessController;
   36   import sun.misc.Cleaner;
   37   import sun.security.action.GetPropertyAction;
   38   
   39   public class FileChannelImpl
   40       extends FileChannel
   41   {
   42       // Memory allocation size for mapping buffers
   43       private static final long allocationGranularity;
   44   
   45       // Used to make native read and write calls
   46       private final FileDispatcher nd;
   47   
   48       // File descriptor
   49       private final FileDescriptor fd;
   50   
   51       // File access mode (immutable)
   52       private final boolean writable;
   53       private final boolean readable;
   54       private final boolean append;
   55   
   56       // Required to prevent finalization of creating stream (immutable)
   57       private final Object parent;
   58   
   59       // Thread-safe set of IDs of native threads, for signalling
   60       private final NativeThreadSet threads = new NativeThreadSet(2);
   61   
   62       // Lock for operations involving position and size
   63       private final Object positionLock = new Object();
   64   
   65       private FileChannelImpl(FileDescriptor fd, boolean readable,
   66                               boolean writable, boolean append, Object parent)
   67       {
   68           this.fd = fd;
   69           this.readable = readable;
   70           this.writable = writable;
   71           this.append = append;
   72           this.parent = parent;
   73           this.nd = new FileDispatcherImpl(append);
   74       }
   75   
   76       // Used by FileInputStream.getChannel() and RandomAccessFile.getChannel()
   77       public static FileChannel open(FileDescriptor fd,
   78                                      boolean readable, boolean writable,
   79                                      Object parent)
   80       {
   81           return new FileChannelImpl(fd, readable, writable, false, parent);
   82       }
   83   
   84       // Used by FileOutputStream.getChannel
   85       public static FileChannel open(FileDescriptor fd,
   86                                      boolean readable, boolean writable,
   87                                      boolean append, Object parent)
   88       {
   89           return new FileChannelImpl(fd, readable, writable, append, parent);
   90       }
   91   
   92       private void ensureOpen() throws IOException {
   93           if (!isOpen())
   94               throw new ClosedChannelException();
   95       }
   96   
   97   
   98       // -- Standard channel operations --
   99   
  100       protected void implCloseChannel() throws IOException {
  101           // Release and invalidate any locks that we still hold
  102           if (fileLockTable != null) {
  103               for (FileLock fl: fileLockTable.removeAll()) {
  104                   synchronized (fl) {
  105                       if (fl.isValid()) {
  106                           nd.release(fd, fl.position(), fl.size());
  107                           ((FileLockImpl)fl).invalidate();
  108                       }
  109                   }
  110               }
  111           }
  112   
  113           nd.preClose(fd);
  114           threads.signalAndWait();
  115   
  116           if (parent != null) {
  117   
  118               // Close the fd via the parent stream's close method.  The parent
  119               // will reinvoke our close method, which is defined in the
  120               // superclass AbstractInterruptibleChannel, but the isOpen logic in
  121               // that method will prevent this method from being reinvoked.
  122               //
  123               ((java.io.Closeable)parent).close();
  124           } else {
  125               nd.close(fd);
  126           }
  127   
  128       }
  129   
  130       public int read(ByteBuffer dst) throws IOException {
  131           ensureOpen();
  132           if (!readable)
  133               throw new NonReadableChannelException();
  134           synchronized (positionLock) {
  135               int n = 0;
  136               int ti = -1;
  137               try {
  138                   begin();
  139                   ti = threads.add();
  140                   if (!isOpen())
  141                       return 0;
  142                   do {
  143                       n = IOUtil.read(fd, dst, -1, nd, positionLock);
  144                   } while ((n == IOStatus.INTERRUPTED) && isOpen());
  145                   return IOStatus.normalize(n);
  146               } finally {
  147                   threads.remove(ti);
  148                   end(n > 0);
  149                   assert IOStatus.check(n);
  150               }
  151           }
  152       }
  153   
  154       public long read(ByteBuffer[] dsts, int offset, int length)
  155           throws IOException
  156       {
  157           if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
  158               throw new IndexOutOfBoundsException();
  159           ensureOpen();
  160           if (!readable)
  161               throw new NonReadableChannelException();
  162           synchronized (positionLock) {
  163               long n = 0;
  164               int ti = -1;
  165               try {
  166                   begin();
  167                   ti = threads.add();
  168                   if (!isOpen())
  169                       return 0;
  170                   do {
  171                       n = IOUtil.read(fd, dsts, offset, length, nd);
  172                   } while ((n == IOStatus.INTERRUPTED) && isOpen());
  173                   return IOStatus.normalize(n);
  174               } finally {
  175                   threads.remove(ti);
  176                   end(n > 0);
  177                   assert IOStatus.check(n);
  178               }
  179           }
  180       }
  181   
  182       public int write(ByteBuffer src) throws IOException {
  183           ensureOpen();
  184           if (!writable)
  185               throw new NonWritableChannelException();
  186           synchronized (positionLock) {
  187               int n = 0;
  188               int ti = -1;
  189               try {
  190                   begin();
  191                   ti = threads.add();
  192                   if (!isOpen())
  193                       return 0;
  194                   do {
  195                       n = IOUtil.write(fd, src, -1, nd, positionLock);
  196                   } while ((n == IOStatus.INTERRUPTED) && isOpen());
  197                   return IOStatus.normalize(n);
  198               } finally {
  199                   threads.remove(ti);
  200                   end(n > 0);
  201                   assert IOStatus.check(n);
  202               }
  203           }
  204       }
  205   
  206       public long write(ByteBuffer[] srcs, int offset, int length)
  207           throws IOException
  208       {
  209           if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
  210               throw new IndexOutOfBoundsException();
  211           ensureOpen();
  212           if (!writable)
  213               throw new NonWritableChannelException();
  214           synchronized (positionLock) {
  215               long n = 0;
  216               int ti = -1;
  217               try {
  218                   begin();
  219                   ti = threads.add();
  220                   if (!isOpen())
  221                       return 0;
  222                   do {
  223                       n = IOUtil.write(fd, srcs, offset, length, nd);
  224                   } while ((n == IOStatus.INTERRUPTED) && isOpen());
  225                   return IOStatus.normalize(n);
  226               } finally {
  227                   threads.remove(ti);
  228                   end(n > 0);
  229                   assert IOStatus.check(n);
  230               }
  231           }
  232       }
  233   
  234       // -- Other operations --
  235   
  236       public long position() throws IOException {
  237           ensureOpen();
  238           synchronized (positionLock) {
  239               long p = -1;
  240               int ti = -1;
  241               try {
  242                   begin();
  243                   ti = threads.add();
  244                   if (!isOpen())
  245                       return 0;
  246                   do {
  247                       // in append-mode then position is advanced to end before writing
  248                       p = (append) ? nd.size(fd) : position0(fd, -1);
  249                   } while ((p == IOStatus.INTERRUPTED) && isOpen());
  250                   return IOStatus.normalize(p);
  251               } finally {
  252                   threads.remove(ti);
  253                   end(p > -1);
  254                   assert IOStatus.check(p);
  255               }
  256           }
  257       }
  258   
  259       public FileChannel position(long newPosition) throws IOException {
  260           ensureOpen();
  261           if (newPosition < 0)
  262               throw new IllegalArgumentException();
  263           synchronized (positionLock) {
  264               long p = -1;
  265               int ti = -1;
  266               try {
  267                   begin();
  268                   ti = threads.add();
  269                   if (!isOpen())
  270                       return null;
  271                   do {
  272                       p  = position0(fd, newPosition);
  273                   } while ((p == IOStatus.INTERRUPTED) && isOpen());
  274                   return this;
  275               } finally {
  276                   threads.remove(ti);
  277                   end(p > -1);
  278                   assert IOStatus.check(p);
  279               }
  280           }
  281       }
  282   
  283       public long size() throws IOException {
  284           ensureOpen();
  285           synchronized (positionLock) {
  286               long s = -1;
  287               int ti = -1;
  288               try {
  289                   begin();
  290                   ti = threads.add();
  291                   if (!isOpen())
  292                       return -1;
  293                   do {
  294                       s = nd.size(fd);
  295                   } while ((s == IOStatus.INTERRUPTED) && isOpen());
  296                   return IOStatus.normalize(s);
  297               } finally {
  298                   threads.remove(ti);
  299                   end(s > -1);
  300                   assert IOStatus.check(s);
  301               }
  302           }
  303       }
  304   
  305       public FileChannel truncate(long size) throws IOException {
  306           ensureOpen();
  307           if (size < 0)
  308               throw new IllegalArgumentException();
  309           if (size > size())
  310               return this;
  311           if (!writable)
  312               throw new NonWritableChannelException();
  313           synchronized (positionLock) {
  314               int rv = -1;
  315               long p = -1;
  316               int ti = -1;
  317               try {
  318                   begin();
  319                   ti = threads.add();
  320                   if (!isOpen())
  321                       return null;
  322   
  323                   // get current position
  324                   do {
  325                       p = position0(fd, -1);
  326                   } while ((p == IOStatus.INTERRUPTED) && isOpen());
  327                   if (!isOpen())
  328                       return null;
  329                   assert p >= 0;
  330   
  331                   // truncate file
  332                   do {
  333                       rv = nd.truncate(fd, size);
  334                   } while ((rv == IOStatus.INTERRUPTED) && isOpen());
  335                   if (!isOpen())
  336                       return null;
  337   
  338                   // set position to size if greater than size
  339                   if (p > size)
  340                       p = size;
  341                   do {
  342                       rv = (int)position0(fd, p);
  343                   } while ((rv == IOStatus.INTERRUPTED) && isOpen());
  344                   return this;
  345               } finally {
  346                   threads.remove(ti);
  347                   end(rv > -1);
  348                   assert IOStatus.check(rv);
  349               }
  350           }
  351       }
  352   
  353       public void force(boolean metaData) throws IOException {
  354           ensureOpen();
  355           int rv = -1;
  356           int ti = -1;
  357           try {
  358               begin();
  359               ti = threads.add();
  360               if (!isOpen())
  361                   return;
  362               do {
  363                   rv = nd.force(fd, metaData);
  364               } while ((rv == IOStatus.INTERRUPTED) && isOpen());
  365           } finally {
  366               threads.remove(ti);
  367               end(rv > -1);
  368               assert IOStatus.check(rv);
  369           }
  370       }
  371   
  372       // Assume at first that the underlying kernel supports sendfile();
  373       // set this to false if we find out later that it doesn't
  374       //
  375       private static volatile boolean transferSupported = true;
  376   
  377       // Assume that the underlying kernel sendfile() will work if the target
  378       // fd is a pipe; set this to false if we find out later that it doesn't
  379       //
  380       private static volatile boolean pipeSupported = true;
  381   
  382       // Assume that the underlying kernel sendfile() will work if the target
  383       // fd is a file; set this to false if we find out later that it doesn't
  384       //
  385       private static volatile boolean fileSupported = true;
  386   
  387       private long transferToDirectly(long position, int icount,
  388                                       WritableByteChannel target)
  389           throws IOException
  390       {
  391           if (!transferSupported)
  392               return IOStatus.UNSUPPORTED;
  393   
  394           FileDescriptor targetFD = null;
  395           if (target instanceof FileChannelImpl) {
  396               if (!fileSupported)
  397                   return IOStatus.UNSUPPORTED_CASE;
  398               targetFD = ((FileChannelImpl)target).fd;
  399           } else if (target instanceof SelChImpl) {
  400               // Direct transfer to pipe causes EINVAL on some configurations
  401               if ((target instanceof SinkChannelImpl) && !pipeSupported)
  402                   return IOStatus.UNSUPPORTED_CASE;
  403               targetFD = ((SelChImpl)target).getFD();
  404           }
  405           if (targetFD == null)
  406               return IOStatus.UNSUPPORTED;
  407           int thisFDVal = IOUtil.fdVal(fd);
  408           int targetFDVal = IOUtil.fdVal(targetFD);
  409           if (thisFDVal == targetFDVal) // Not supported on some configurations
  410               return IOStatus.UNSUPPORTED;
  411   
  412           long n = -1;
  413           int ti = -1;
  414           try {
  415               begin();
  416               ti = threads.add();
  417               if (!isOpen())
  418                   return -1;
  419               do {
  420                   n = transferTo0(thisFDVal, position, icount, targetFDVal);
  421               } while ((n == IOStatus.INTERRUPTED) && isOpen());
  422               if (n == IOStatus.UNSUPPORTED_CASE) {
  423                   if (target instanceof SinkChannelImpl)
  424                       pipeSupported = false;
  425                   if (target instanceof FileChannelImpl)
  426                       fileSupported = false;
  427                   return IOStatus.UNSUPPORTED_CASE;
  428               }
  429               if (n == IOStatus.UNSUPPORTED) {
  430                   // Don't bother trying again
  431                   transferSupported = false;
  432                   return IOStatus.UNSUPPORTED;
  433               }
  434               return IOStatus.normalize(n);
  435           } finally {
  436               threads.remove(ti);
  437               end (n > -1);
  438           }
  439       }
  440   
  441       // Maximum size to map when using a mapped buffer
  442       private static final long MAPPED_TRANSFER_SIZE = 8L*1024L*1024L;
  443   
  444       private long transferToTrustedChannel(long position, long count,
  445                                             WritableByteChannel target)
  446           throws IOException
  447       {
  448           boolean isSelChImpl = (target instanceof SelChImpl);
  449           if (!((target instanceof FileChannelImpl) || isSelChImpl))
  450               return IOStatus.UNSUPPORTED;
  451   
  452           // Trusted target: Use a mapped buffer
  453           long remaining = count;
  454           while (remaining > 0L) {
  455               long size = Math.min(remaining, MAPPED_TRANSFER_SIZE);
  456               try {
  457                   MappedByteBuffer dbb = map(MapMode.READ_ONLY, position, size);
  458                   try {
  459                       // ## Bug: Closing this channel will not terminate the write
  460                       int n = target.write(dbb);
  461                       assert n >= 0;
  462                       remaining -= n;
  463                       if (isSelChImpl) {
  464                           // one attempt to write to selectable channel
  465                           break;
  466                       }
  467                       assert n > 0;
  468                       position += n;
  469                   } finally {
  470                       unmap(dbb);
  471                   }
  472               } catch (ClosedByInterruptException e) {
  473                   // target closed by interrupt as ClosedByInterruptException needs
  474                   // to be thrown after closing this channel.
  475                   assert !target.isOpen();
  476                   try {
  477                       close();
  478                   } catch (Throwable suppressed) {
  479                       e.addSuppressed(suppressed);
  480                   }
  481                   throw e;
  482               } catch (IOException ioe) {
  483                   // Only throw exception if no bytes have been written
  484                   if (remaining == count)
  485                       throw ioe;
  486                   break;
  487               }
  488           }
  489           return count - remaining;
  490       }
  491   
  492       private long transferToArbitraryChannel(long position, int icount,
  493                                               WritableByteChannel target)
  494           throws IOException
  495       {
  496           // Untrusted target: Use a newly-erased buffer
  497           int c = Math.min(icount, TRANSFER_SIZE);
  498           ByteBuffer bb = Util.getTemporaryDirectBuffer(c);
  499           long tw = 0;                    // Total bytes written
  500           long pos = position;
  501           try {
  502               Util.erase(bb);
  503               while (tw < icount) {
  504                   bb.limit(Math.min((int)(icount - tw), TRANSFER_SIZE));
  505                   int nr = read(bb, pos);
  506                   if (nr <= 0)
  507                       break;
  508                   bb.flip();
  509                   // ## Bug: Will block writing target if this channel
  510                   // ##      is asynchronously closed
  511                   int nw = target.write(bb);
  512                   tw += nw;
  513                   if (nw != nr)
  514                       break;
  515                   pos += nw;
  516                   bb.clear();
  517               }
  518               return tw;
  519           } catch (IOException x) {
  520               if (tw > 0)
  521                   return tw;
  522               throw x;
  523           } finally {
  524               Util.releaseTemporaryDirectBuffer(bb);
  525           }
  526       }
  527   
  528       public long transferTo(long position, long count,
  529                              WritableByteChannel target)
  530           throws IOException
  531       {
  532           ensureOpen();
  533           if (!target.isOpen())
  534               throw new ClosedChannelException();
  535           if (!readable)
  536               throw new NonReadableChannelException();
  537           if (target instanceof FileChannelImpl &&
  538               !((FileChannelImpl)target).writable)
  539               throw new NonWritableChannelException();
  540           if ((position < 0) || (count < 0))
  541               throw new IllegalArgumentException();
  542           long sz = size();
  543           if (position > sz)
  544               return 0;
  545           int icount = (int)Math.min(count, Integer.MAX_VALUE);
  546           if ((sz - position) < icount)
  547               icount = (int)(sz - position);
  548   
  549           long n;
  550   
  551           // Attempt a direct transfer, if the kernel supports it
  552           if ((n = transferToDirectly(position, icount, target)) >= 0)
  553               return n;
  554   
  555           // Attempt a mapped transfer, but only to trusted channel types
  556           if ((n = transferToTrustedChannel(position, icount, target)) >= 0)
  557               return n;
  558   
  559           // Slow path for untrusted targets
  560           return transferToArbitraryChannel(position, icount, target);
  561       }
  562   
  563       private long transferFromFileChannel(FileChannelImpl src,
  564                                            long position, long count)
  565           throws IOException
  566       {
  567           if (!src.readable)
  568               throw new NonReadableChannelException();
  569           synchronized (src.positionLock) {
  570               long pos = src.position();
  571               long max = Math.min(count, src.size() - pos);
  572   
  573               long remaining = max;
  574               long p = pos;
  575               while (remaining > 0L) {
  576                   long size = Math.min(remaining, MAPPED_TRANSFER_SIZE);
  577                   // ## Bug: Closing this channel will not terminate the write
  578                   MappedByteBuffer bb = src.map(MapMode.READ_ONLY, p, size);
  579                   try {
  580                       long n = write(bb, position);
  581                       assert n > 0;
  582                       p += n;
  583                       position += n;
  584                       remaining -= n;
  585                   } catch (IOException ioe) {
  586                       // Only throw exception if no bytes have been written
  587                       if (remaining == max)
  588                           throw ioe;
  589                       break;
  590                   } finally {
  591                       unmap(bb);
  592                   }
  593               }
  594               long nwritten = max - remaining;
  595               src.position(pos + nwritten);
  596               return nwritten;
  597           }
  598       }
  599   
  600       private static final int TRANSFER_SIZE = 8192;
  601   
  602       private long transferFromArbitraryChannel(ReadableByteChannel src,
  603                                                 long position, long count)
  604           throws IOException
  605       {
  606           // Untrusted target: Use a newly-erased buffer
  607           int c = (int)Math.min(count, TRANSFER_SIZE);
  608           ByteBuffer bb = Util.getTemporaryDirectBuffer(c);
  609           long tw = 0;                    // Total bytes written
  610           long pos = position;
  611           try {
  612               Util.erase(bb);
  613               while (tw < count) {
  614                   bb.limit((int)Math.min((count - tw), (long)TRANSFER_SIZE));
  615                   // ## Bug: Will block reading src if this channel
  616                   // ##      is asynchronously closed
  617                   int nr = src.read(bb);
  618                   if (nr <= 0)
  619                       break;
  620                   bb.flip();
  621                   int nw = write(bb, pos);
  622                   tw += nw;
  623                   if (nw != nr)
  624                       break;
  625                   pos += nw;
  626                   bb.clear();
  627               }
  628               return tw;
  629           } catch (IOException x) {
  630               if (tw > 0)
  631                   return tw;
  632               throw x;
  633           } finally {
  634               Util.releaseTemporaryDirectBuffer(bb);
  635           }
  636       }
  637   
  638       public long transferFrom(ReadableByteChannel src,
  639                                long position, long count)
  640           throws IOException
  641       {
  642           ensureOpen();
  643           if (!src.isOpen())
  644               throw new ClosedChannelException();
  645           if (!writable)
  646               throw new NonWritableChannelException();
  647           if ((position < 0) || (count < 0))
  648               throw new IllegalArgumentException();
  649           if (position > size())
  650               return 0;
  651           if (src instanceof FileChannelImpl)
  652              return transferFromFileChannel((FileChannelImpl)src,
  653                                             position, count);
  654   
  655           return transferFromArbitraryChannel(src, position, count);
  656       }
  657   
  658       public int read(ByteBuffer dst, long position) throws IOException {
  659           if (dst == null)
  660               throw new NullPointerException();
  661           if (position < 0)
  662               throw new IllegalArgumentException("Negative position");
  663           if (!readable)
  664               throw new NonReadableChannelException();
  665           ensureOpen();
  666           int n = 0;
  667           int ti = -1;
  668           try {
  669               begin();
  670               ti = threads.add();
  671               if (!isOpen())
  672                   return -1;
  673               do {
  674                   n = IOUtil.read(fd, dst, position, nd, positionLock);
  675               } while ((n == IOStatus.INTERRUPTED) && isOpen());
  676               return IOStatus.normalize(n);
  677           } finally {
  678               threads.remove(ti);
  679               end(n > 0);
  680               assert IOStatus.check(n);
  681           }
  682       }
  683   
  684       public int write(ByteBuffer src, long position) throws IOException {
  685           if (src == null)
  686               throw new NullPointerException();
  687           if (position < 0)
  688               throw new IllegalArgumentException("Negative position");
  689           if (!writable)
  690               throw new NonWritableChannelException();
  691           ensureOpen();
  692           int n = 0;
  693           int ti = -1;
  694           try {
  695               begin();
  696               ti = threads.add();
  697               if (!isOpen())
  698                   return -1;
  699               do {
  700                   n = IOUtil.write(fd, src, position, nd, positionLock);
  701               } while ((n == IOStatus.INTERRUPTED) && isOpen());
  702               return IOStatus.normalize(n);
  703           } finally {
  704               threads.remove(ti);
  705               end(n > 0);
  706               assert IOStatus.check(n);
  707           }
  708       }
  709   
  710   
  711       // -- Memory-mapped buffers --
  712   
  713       private static class Unmapper
  714           implements Runnable
  715       {
  716           // may be required to close file
  717           private static final NativeDispatcher nd = new FileDispatcherImpl();
  718   
  719           // keep track of mapped buffer usage
  720           static volatile int count;
  721           static volatile long totalSize;
  722           static volatile long totalCapacity;
  723   
  724           private volatile long address;
  725           private final long size;
  726           private final int cap;
  727           private final FileDescriptor fd;
  728   
  729           private Unmapper(long address, long size, int cap,
  730                            FileDescriptor fd)
  731           {
  732               assert (address != 0);
  733               this.address = address;
  734               this.size = size;
  735               this.cap = cap;
  736               this.fd = fd;
  737   
  738               synchronized (Unmapper.class) {
  739                   count++;
  740                   totalSize += size;
  741                   totalCapacity += cap;
  742               }
  743           }
  744   
  745           public void run() {
  746               if (address == 0)
  747                   return;
  748               unmap0(address, size);
  749               address = 0;
  750   
  751               // if this mapping has a valid file descriptor then we close it
  752               if (fd.valid()) {
  753                   try {
  754                       nd.close(fd);
  755                   } catch (IOException ignore) {
  756                       // nothing we can do
  757                   }
  758               }
  759   
  760               synchronized (Unmapper.class) {
  761                   count--;
  762                   totalSize -= size;
  763                   totalCapacity -= cap;
  764               }
  765           }
  766       }
  767   
  768       private static void unmap(MappedByteBuffer bb) {
  769           Cleaner cl = ((DirectBuffer)bb).cleaner();
  770           if (cl != null)
  771               cl.clean();
  772       }
  773   
  774       private static final int MAP_RO = 0;
  775       private static final int MAP_RW = 1;
  776       private static final int MAP_PV = 2;
  777   
  778       public MappedByteBuffer map(MapMode mode, long position, long size)
  779           throws IOException
  780       {
  781           ensureOpen();
  782           if (position < 0L)
  783               throw new IllegalArgumentException("Negative position");
  784           if (size < 0L)
  785               throw new IllegalArgumentException("Negative size");
  786           if (position + size < 0)
  787               throw new IllegalArgumentException("Position + size overflow");
  788           if (size > Integer.MAX_VALUE)
  789               throw new IllegalArgumentException("Size exceeds Integer.MAX_VALUE");
  790           int imode = -1;
  791           if (mode == MapMode.READ_ONLY)
  792               imode = MAP_RO;
  793           else if (mode == MapMode.READ_WRITE)
  794               imode = MAP_RW;
  795           else if (mode == MapMode.PRIVATE)
  796               imode = MAP_PV;
  797           assert (imode >= 0);
  798           if ((mode != MapMode.READ_ONLY) && !writable)
  799               throw new NonWritableChannelException();
  800           if (!readable)
  801               throw new NonReadableChannelException();
  802   
  803           long addr = -1;
  804           int ti = -1;
  805           try {
  806               begin();
  807               ti = threads.add();
  808               if (!isOpen())
  809                   return null;
  810               if (size() < position + size) { // Extend file size
  811                   if (!writable) {
  812                       throw new IOException("Channel not open for writing " +
  813                           "- cannot extend file to required size");
  814                   }
  815                   int rv;
  816                   do {
  817                       rv = nd.truncate(fd, position + size);
  818                   } while ((rv == IOStatus.INTERRUPTED) && isOpen());
  819               }
  820               if (size == 0) {
  821                   addr = 0;
  822                   // a valid file descriptor is not required
  823                   FileDescriptor dummy = new FileDescriptor();
  824                   if ((!writable) || (imode == MAP_RO))
  825                       return Util.newMappedByteBufferR(0, 0, dummy, null);
  826                   else
  827                       return Util.newMappedByteBuffer(0, 0, dummy, null);
  828               }
  829   
  830               int pagePosition = (int)(position % allocationGranularity);
  831               long mapPosition = position - pagePosition;
  832               long mapSize = size + pagePosition;
  833               try {
  834                   // If no exception was thrown from map0, the address is valid
  835                   addr = map0(imode, mapPosition, mapSize);
  836               } catch (OutOfMemoryError x) {
  837                   // An OutOfMemoryError may indicate that we've exhausted memory
  838                   // so force gc and re-attempt map
  839                   System.gc();
  840                   try {
  841                       Thread.sleep(100);
  842                   } catch (InterruptedException y) {
  843                       Thread.currentThread().interrupt();
  844                   }
  845                   try {
  846                       addr = map0(imode, mapPosition, mapSize);
  847                   } catch (OutOfMemoryError y) {
  848                       // After a second OOME, fail
  849                       throw new IOException("Map failed", y);
  850                   }
  851               }
  852   
  853               // On Windows, and potentially other platforms, we need an open
  854               // file descriptor for some mapping operations.
  855               FileDescriptor mfd;
  856               try {
  857                   mfd = nd.duplicateForMapping(fd);
  858               } catch (IOException ioe) {
  859                   unmap0(addr, mapSize);
  860                   throw ioe;
  861               }
  862   
  863               assert (IOStatus.checkAll(addr));
  864               assert (addr % allocationGranularity == 0);
  865               int isize = (int)size;
  866               Unmapper um = new Unmapper(addr, mapSize, isize, mfd);
  867               if ((!writable) || (imode == MAP_RO)) {
  868                   return Util.newMappedByteBufferR(isize,
  869                                                    addr + pagePosition,
  870                                                    mfd,
  871                                                    um);
  872               } else {
  873                   return Util.newMappedByteBuffer(isize,
  874                                                   addr + pagePosition,
  875                                                   mfd,
  876                                                   um);
  877               }
  878           } finally {
  879               threads.remove(ti);
  880               end(IOStatus.checkAll(addr));
  881           }
  882       }
  883   
  884       /**
  885        * Invoked by sun.management.ManagementFactoryHelper to create the management
  886        * interface for mapped buffers.
  887        */
  888       public static sun.misc.JavaNioAccess.BufferPool getMappedBufferPool() {
  889           return new sun.misc.JavaNioAccess.BufferPool() {
  890               @Override
  891               public String getName() {
  892                   return "mapped";
  893               }
  894               @Override
  895               public long getCount() {
  896                   return Unmapper.count;
  897               }
  898               @Override
  899               public long getTotalCapacity() {
  900                   return Unmapper.totalCapacity;
  901               }
  902               @Override
  903               public long getMemoryUsed() {
  904                   return Unmapper.totalSize;
  905               }
  906           };
  907       }
  908   
  909       // -- Locks --
  910   
  911   
  912   
  913       // keeps track of locks on this file
  914       private volatile FileLockTable fileLockTable;
  915   
  916       // indicates if file locks are maintained system-wide (as per spec)
  917       private static boolean isSharedFileLockTable;
  918   
  919       // indicates if the disableSystemWideOverlappingFileLockCheck property
  920       // has been checked
  921       private static volatile boolean propertyChecked;
  922   
  923       // The lock list in J2SE 1.4/5.0 was local to each FileChannel instance so
  924       // the overlap check wasn't system wide when there were multiple channels to
  925       // the same file. This property is used to get 1.4/5.0 behavior if desired.
  926       private static boolean isSharedFileLockTable() {
  927           if (!propertyChecked) {
  928               synchronized (FileChannelImpl.class) {
  929                   if (!propertyChecked) {
  930                       String value = AccessController.doPrivileged(
  931                           new GetPropertyAction(
  932                               "sun.nio.ch.disableSystemWideOverlappingFileLockCheck"));
  933                       isSharedFileLockTable = ((value == null) || value.equals("false"));
  934                       propertyChecked = true;
  935                   }
  936               }
  937           }
  938           return isSharedFileLockTable;
  939       }
  940   
  941       private FileLockTable fileLockTable() throws IOException {
  942           if (fileLockTable == null) {
  943               synchronized (this) {
  944                   if (fileLockTable == null) {
  945                       if (isSharedFileLockTable()) {
  946                           int ti = threads.add();
  947                           try {
  948                               ensureOpen();
  949                               fileLockTable = FileLockTable.newSharedFileLockTable(this, fd);
  950                           } finally {
  951                               threads.remove(ti);
  952                           }
  953                       } else {
  954                           fileLockTable = new SimpleFileLockTable();
  955                       }
  956                   }
  957               }
  958           }
  959           return fileLockTable;
  960       }
  961   
  962       public FileLock lock(long position, long size, boolean shared)
  963           throws IOException
  964       {
  965           ensureOpen();
  966           if (shared && !readable)
  967               throw new NonReadableChannelException();
  968           if (!shared && !writable)
  969               throw new NonWritableChannelException();
  970           FileLockImpl fli = new FileLockImpl(this, position, size, shared);
  971           FileLockTable flt = fileLockTable();
  972           flt.add(fli);
  973           boolean completed = false;
  974           int ti = -1;
  975           try {
  976               begin();
  977               ti = threads.add();
  978               if (!isOpen())
  979                   return null;
  980               int n;
  981               do {
  982                   n = nd.lock(fd, true, position, size, shared);
  983               } while ((n == FileDispatcher.INTERRUPTED) && isOpen());
  984               if (isOpen()) {
  985                   if (n == FileDispatcher.RET_EX_LOCK) {
  986                       assert shared;
  987                       FileLockImpl fli2 = new FileLockImpl(this, position, size,
  988                                                            false);
  989                       flt.replace(fli, fli2);
  990                       fli = fli2;
  991                   }
  992                   completed = true;
  993               }
  994           } finally {
  995               if (!completed)
  996                   flt.remove(fli);
  997               threads.remove(ti);
  998               try {
  999                   end(completed);
 1000               } catch (ClosedByInterruptException e) {
 1001                   throw new FileLockInterruptionException();
 1002               }
 1003           }
 1004           return fli;
 1005       }
 1006   
 1007       public FileLock tryLock(long position, long size, boolean shared)
 1008           throws IOException
 1009       {
 1010           ensureOpen();
 1011           if (shared && !readable)
 1012               throw new NonReadableChannelException();
 1013           if (!shared && !writable)
 1014               throw new NonWritableChannelException();
 1015           FileLockImpl fli = new FileLockImpl(this, position, size, shared);
 1016           FileLockTable flt = fileLockTable();
 1017           flt.add(fli);
 1018           int result;
 1019   
 1020           int ti = threads.add();
 1021           try {
 1022               try {
 1023                   ensureOpen();
 1024                   result = nd.lock(fd, false, position, size, shared);
 1025               } catch (IOException e) {
 1026                   flt.remove(fli);
 1027                   throw e;
 1028               }
 1029               if (result == FileDispatcher.NO_LOCK) {
 1030                   flt.remove(fli);
 1031                   return null;
 1032               }
 1033               if (result == FileDispatcher.RET_EX_LOCK) {
 1034                   assert shared;
 1035                   FileLockImpl fli2 = new FileLockImpl(this, position, size,
 1036                                                        false);
 1037                   flt.replace(fli, fli2);
 1038                   return fli2;
 1039               }
 1040               return fli;
 1041           } finally {
 1042               threads.remove(ti);
 1043           }
 1044       }
 1045   
 1046       void release(FileLockImpl fli) throws IOException {
 1047           int ti = threads.add();
 1048           try {
 1049               ensureOpen();
 1050               nd.release(fd, fli.position(), fli.size());
 1051           } finally {
 1052               threads.remove(ti);
 1053           }
 1054           assert fileLockTable != null;
 1055           fileLockTable.remove(fli);
 1056       }
 1057   
 1058       // -- File lock support --
 1059   
 1060       /**
 1061        * A simple file lock table that maintains a list of FileLocks obtained by a
 1062        * FileChannel. Use to get 1.4/5.0 behaviour.
 1063        */
 1064       private static class SimpleFileLockTable extends FileLockTable {
 1065           // synchronize on list for access
 1066           private final List<FileLock> lockList = new ArrayList<FileLock>(2);
 1067   
 1068           public SimpleFileLockTable() {
 1069           }
 1070   
 1071           private void checkList(long position, long size)
 1072               throws OverlappingFileLockException
 1073           {
 1074               assert Thread.holdsLock(lockList);
 1075               for (FileLock fl: lockList) {
 1076                   if (fl.overlaps(position, size)) {
 1077                       throw new OverlappingFileLockException();
 1078                   }
 1079               }
 1080           }
 1081   
 1082           public void add(FileLock fl) throws OverlappingFileLockException {
 1083               synchronized (lockList) {
 1084                   checkList(fl.position(), fl.size());
 1085                   lockList.add(fl);
 1086               }
 1087           }
 1088   
 1089           public void remove(FileLock fl) {
 1090               synchronized (lockList) {
 1091                   lockList.remove(fl);
 1092               }
 1093           }
 1094   
 1095           public List<FileLock> removeAll() {
 1096               synchronized(lockList) {
 1097                   List<FileLock> result = new ArrayList<FileLock>(lockList);
 1098                   lockList.clear();
 1099                   return result;
 1100               }
 1101           }
 1102   
 1103           public void replace(FileLock fl1, FileLock fl2) {
 1104               synchronized (lockList) {
 1105                   lockList.remove(fl1);
 1106                   lockList.add(fl2);
 1107               }
 1108           }
 1109       }
 1110   
 1111       // -- Native methods --
 1112   
 1113       // Creates a new mapping
 1114       private native long map0(int prot, long position, long length)
 1115           throws IOException;
 1116   
 1117       // Removes an existing mapping
 1118       private static native int unmap0(long address, long length);
 1119   
 1120       // Transfers from src to dst, or returns -2 if kernel can't do that
 1121       private native long transferTo0(int src, long position, long count, int dst);
 1122   
 1123       // Sets or reports this file's position
 1124       // If offset is -1, the current position is returned
 1125       // otherwise the position is set to offset
 1126       private native long position0(FileDescriptor fd, long offset);
 1127   
 1128       // Caches fieldIDs
 1129       private static native long initIDs();
 1130   
 1131       static {
 1132           Util.load();
 1133           allocationGranularity = initIDs();
 1134       }
 1135   
 1136   }

转载于:https://my.oschina.net/ielts0909/blog/87186

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值