Home | History | Annotate | Download | only in io
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
      4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      5  *
      6  * This code is free software; you can redistribute it and/or modify it
      7  * under the terms of the GNU General Public License version 2 only, as
      8  * published by the Free Software Foundation.  Oracle designates this
      9  * particular file as subject to the "Classpath" exception as provided
     10  * by Oracle in the LICENSE file that accompanied this code.
     11  *
     12  * This code is distributed in the hope that it will be useful, but WITHOUT
     13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     15  * version 2 for more details (a copy is included in the LICENSE file that
     16  * accompanied this code).
     17  *
     18  * You should have received a copy of the GNU General Public License version
     19  * 2 along with this work; if not, write to the Free Software Foundation,
     20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     21  *
     22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     23  * or visit www.oracle.com if you need additional information or have any
     24  * questions.
     25  */
     26 
     27 package java.io;
     28 
     29 import java.nio.channels.FileChannel;
     30 
     31 import dalvik.system.BlockGuard;
     32 import dalvik.system.CloseGuard;
     33 import sun.nio.ch.FileChannelImpl;
     34 import libcore.io.IoBridge;
     35 import libcore.io.IoTracker;
     36 
     37 
     38 /**
     39  * A <code>FileInputStream</code> obtains input bytes
     40  * from a file in a file system. What files
     41  * are  available depends on the host environment.
     42  *
     43  * <p><code>FileInputStream</code> is meant for reading streams of raw bytes
     44  * such as image data. For reading streams of characters, consider using
     45  * <code>FileReader</code>.
     46  *
     47  * @author  Arthur van Hoff
     48  * @see     java.io.File
     49  * @see     java.io.FileDescriptor
     50  * @see     java.io.FileOutputStream
     51  * @see     java.nio.file.Files#newInputStream
     52  * @since   JDK1.0
     53  */
     54 public
     55 class FileInputStream extends InputStream
     56 {
     57     /* File Descriptor - handle to the open file */
     58     private final FileDescriptor fd;
     59 
     60     /**
     61      * The path of the referenced file
     62      * (null if the stream is created with a file descriptor)
     63      */
     64     private final String path;
     65 
     66     private FileChannel channel = null;
     67 
     68     private final Object closeLock = new Object();
     69     private volatile boolean closed = false;
     70     private final boolean isFdOwner;
     71 
     72     private final CloseGuard guard = CloseGuard.get();
     73     private final IoTracker tracker = new IoTracker();
     74 
     75     /**
     76      * Creates a <code>FileInputStream</code> by
     77      * opening a connection to an actual file,
     78      * the file named by the path name <code>name</code>
     79      * in the file system.  A new <code>FileDescriptor</code>
     80      * object is created to represent this file
     81      * connection.
     82      * <p>
     83      * First, if there is a security
     84      * manager, its <code>checkRead</code> method
     85      * is called with the <code>name</code> argument
     86      * as its argument.
     87      * <p>
     88      * If the named file does not exist, is a directory rather than a regular
     89      * file, or for some other reason cannot be opened for reading then a
     90      * <code>FileNotFoundException</code> is thrown.
     91      *
     92      * @param      name   the system-dependent file name.
     93      * @exception  FileNotFoundException  if the file does not exist,
     94      *                   is a directory rather than a regular file,
     95      *                   or for some other reason cannot be opened for
     96      *                   reading.
     97      * @exception  SecurityException      if a security manager exists and its
     98      *               <code>checkRead</code> method denies read access
     99      *               to the file.
    100      * @see        java.lang.SecurityManager#checkRead(java.lang.String)
    101      */
    102     public FileInputStream(String name) throws FileNotFoundException {
    103         this(name != null ? new File(name) : null);
    104     }
    105 
    106     /**
    107      * Creates a <code>FileInputStream</code> by
    108      * opening a connection to an actual file,
    109      * the file named by the <code>File</code>
    110      * object <code>file</code> in the file system.
    111      * A new <code>FileDescriptor</code> object
    112      * is created to represent this file connection.
    113      * <p>
    114      * First, if there is a security manager,
    115      * its <code>checkRead</code> method  is called
    116      * with the path represented by the <code>file</code>
    117      * argument as its argument.
    118      * <p>
    119      * If the named file does not exist, is a directory rather than a regular
    120      * file, or for some other reason cannot be opened for reading then a
    121      * <code>FileNotFoundException</code> is thrown.
    122      *
    123      * @param      file   the file to be opened for reading.
    124      * @exception  FileNotFoundException  if the file does not exist,
    125      *                   is a directory rather than a regular file,
    126      *                   or for some other reason cannot be opened for
    127      *                   reading.
    128      * @exception  SecurityException      if a security manager exists and its
    129      *               <code>checkRead</code> method denies read access to the file.
    130      * @see        java.io.File#getPath()
    131      * @see        java.lang.SecurityManager#checkRead(java.lang.String)
    132      */
    133     public FileInputStream(File file) throws FileNotFoundException {
    134         String name = (file != null ? file.getPath() : null);
    135         SecurityManager security = System.getSecurityManager();
    136         if (security != null) {
    137             security.checkRead(name);
    138         }
    139         if (name == null) {
    140             throw new NullPointerException();
    141         }
    142         if (file.isInvalid()) {
    143             throw new FileNotFoundException("Invalid file path");
    144         }
    145         fd = new FileDescriptor();
    146         isFdOwner = true;
    147         this.path = name;
    148 
    149         BlockGuard.getThreadPolicy().onReadFromDisk();
    150         open(name);
    151         guard.open("close");
    152     }
    153 
    154     /**
    155      * Creates a <code>FileInputStream</code> by using the file descriptor
    156      * <code>fdObj</code>, which represents an existing connection to an
    157      * actual file in the file system.
    158      * <p>
    159      * If there is a security manager, its <code>checkRead</code> method is
    160      * called with the file descriptor <code>fdObj</code> as its argument to
    161      * see if it's ok to read the file descriptor. If read access is denied
    162      * to the file descriptor a <code>SecurityException</code> is thrown.
    163      * <p>
    164      * If <code>fdObj</code> is null then a <code>NullPointerException</code>
    165      * is thrown.
    166      * <p>
    167      * This constructor does not throw an exception if <code>fdObj</code>
    168      * is {@link java.io.FileDescriptor#valid() invalid}.
    169      * However, if the methods are invoked on the resulting stream to attempt
    170      * I/O on the stream, an <code>IOException</code> is thrown.
    171      *
    172      * @param      fdObj   the file descriptor to be opened for reading.
    173      */
    174     public FileInputStream(FileDescriptor fdObj) {
    175         this(fdObj, false /* isFdOwner */);
    176     }
    177 
    178     /** @hide */
    179     public FileInputStream(FileDescriptor fdObj, boolean isFdOwner) {
    180         if (fdObj == null) {
    181             throw new NullPointerException("fdObj == null");
    182         }
    183         fd = fdObj;
    184         this.isFdOwner = isFdOwner;
    185         path = null;
    186     }
    187 
    188     /**
    189      * Opens the specified file for reading.
    190      * @param name the name of the file
    191      */
    192     private native void open0(String name) throws FileNotFoundException;
    193 
    194     // wrap native call to allow instrumentation
    195     /**
    196      * Opens the specified file for reading.
    197      * @param name the name of the file
    198      */
    199     private void open(String name) throws FileNotFoundException {
    200         open0(name);
    201     }
    202 
    203     /**
    204      * Reads a byte of data from this input stream. This method blocks
    205      * if no input is yet available.
    206      *
    207      * @return     the next byte of data, or <code>-1</code> if the end of the
    208      *             file is reached.
    209      * @exception  IOException  if an I/O error occurs.
    210      */
    211     public int read() throws IOException {
    212         byte[] b = new byte[1];
    213         return (read(b, 0, 1) != -1) ? b[0] & 0xff : -1;
    214     }
    215 
    216     /**
    217      * Reads up to <code>b.length</code> bytes of data from this input
    218      * stream into an array of bytes. This method blocks until some input
    219      * is available.
    220      *
    221      * @param      b   the buffer into which the data is read.
    222      * @return     the total number of bytes read into the buffer, or
    223      *             <code>-1</code> if there is no more data because the end of
    224      *             the file has been reached.
    225      * @exception  IOException  if an I/O error occurs.
    226      */
    227     public int read(byte b[]) throws IOException {
    228         return read(b, 0, b.length);
    229     }
    230 
    231     /**
    232      * Reads up to <code>len</code> bytes of data from this input stream
    233      * into an array of bytes. If <code>len</code> is not zero, the method
    234      * blocks until some input is available; otherwise, no
    235      * bytes are read and <code>0</code> is returned.
    236      *
    237      * @param      b     the buffer into which the data is read.
    238      * @param      off   the start offset in the destination array <code>b</code>
    239      * @param      len   the maximum number of bytes read.
    240      * @return     the total number of bytes read into the buffer, or
    241      *             <code>-1</code> if there is no more data because the end of
    242      *             the file has been reached.
    243      * @exception  NullPointerException If <code>b</code> is <code>null</code>.
    244      * @exception  IndexOutOfBoundsException If <code>off</code> is negative,
    245      * <code>len</code> is negative, or <code>len</code> is greater than
    246      * <code>b.length - off</code>
    247      * @exception  IOException  if an I/O error occurs.
    248      */
    249     public int read(byte b[], int off, int len) throws IOException {
    250         if (closed && len > 0) {
    251             throw new IOException("Stream Closed");
    252         }
    253         tracker.trackIo(len);
    254         return IoBridge.read(fd, b, off, len);
    255     }
    256 
    257     /**
    258      * Skips over and discards <code>n</code> bytes of data from the
    259      * input stream.
    260      *
    261      * <p>The <code>skip</code> method may, for a variety of
    262      * reasons, end up skipping over some smaller number of bytes,
    263      * possibly <code>0</code>. If <code>n</code> is negative, the method
    264      * will try to skip backwards. In case the backing file does not support
    265      * backward skip at its current position, an <code>IOException</code> is
    266      * thrown. The actual number of bytes skipped is returned. If it skips
    267      * forwards, it returns a positive value. If it skips backwards, it
    268      * returns a negative value.
    269      *
    270      * <p>This method may skip more bytes than what are remaining in the
    271      * backing file. This produces no exception and the number of bytes skipped
    272      * may include some number of bytes that were beyond the EOF of the
    273      * backing file. Attempting to read from the stream after skipping past
    274      * the end will result in -1 indicating the end of the file.
    275      *
    276      * @param      n   the number of bytes to be skipped.
    277      * @return     the actual number of bytes skipped.
    278      * @exception  IOException  if n is negative, if the stream does not
    279      *             support seek, or if an I/O error occurs.
    280      */
    281     public long skip(long n) throws IOException {
    282         if (closed) {
    283             throw new IOException("Stream Closed");
    284         }
    285 
    286         try {
    287             BlockGuard.getThreadPolicy().onReadFromDisk();
    288             return skip0(n);
    289         } catch(UseManualSkipException e) {
    290             return super.skip(n);
    291         }
    292     }
    293 
    294     private native long skip0(long n) throws IOException, UseManualSkipException;
    295 
    296     /*
    297      * Used to force manual skip when FileInputStream operates on pipe
    298      */
    299     private static class UseManualSkipException extends Exception {
    300     }
    301 
    302     /**
    303      * Returns an estimate of the number of remaining bytes that can be read (or
    304      * skipped over) from this input stream without blocking by the next
    305      * invocation of a method for this input stream. Returns 0 when the file
    306      * position is beyond EOF. The next invocation might be the same thread
    307      * or another thread. A single read or skip of this many bytes will not
    308      * block, but may read or skip fewer bytes.
    309      *
    310      * <p> In some cases, a non-blocking read (or skip) may appear to be
    311      * blocked when it is merely slow, for example when reading large
    312      * files over slow networks.
    313      *
    314      * @return     an estimate of the number of remaining bytes that can be read
    315      *             (or skipped over) from this input stream without blocking.
    316      * @exception  IOException  if this file input stream has been closed by calling
    317      *             {@code close} or an I/O error occurs.
    318      */
    319     public int available() throws IOException {
    320         if (closed) {
    321             throw new IOException("Stream Closed");
    322         }
    323 
    324         return available0();
    325     }
    326 
    327     private native int available0() throws IOException;
    328 
    329     /**
    330      * Closes this file input stream and releases any system resources
    331      * associated with the stream.
    332      *
    333      * <p> If this stream has an associated channel then the channel is closed
    334      * as well.
    335      *
    336      * @exception  IOException  if an I/O error occurs.
    337      *
    338      * @revised 1.4
    339      * @spec JSR-51
    340      */
    341     public void close() throws IOException {
    342         synchronized (closeLock) {
    343             if (closed) {
    344                 return;
    345             }
    346             closed = true;
    347         }
    348 
    349         guard.close();
    350 
    351         if (channel != null) {
    352             /*
    353              * Decrement the FD use count associated with the channel
    354              * The use count is incremented whenever a new channel
    355              * is obtained from this stream.
    356              */
    357            channel.close();
    358         }
    359 
    360         if (isFdOwner) {
    361             IoBridge.closeAndSignalBlockedThreads(fd);
    362         }
    363     }
    364 
    365     /**
    366      * Returns the <code>FileDescriptor</code>
    367      * object  that represents the connection to
    368      * the actual file in the file system being
    369      * used by this <code>FileInputStream</code>.
    370      *
    371      * @return     the file descriptor object associated with this stream.
    372      * @exception  IOException  if an I/O error occurs.
    373      * @see        java.io.FileDescriptor
    374      */
    375     public final FileDescriptor getFD() throws IOException {
    376         if (fd != null) {
    377             return fd;
    378         }
    379         throw new IOException();
    380     }
    381 
    382     /**
    383      * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
    384      * object associated with this file input stream.
    385      *
    386      * <p> The initial {@link java.nio.channels.FileChannel#position()
    387      * position} of the returned channel will be equal to the
    388      * number of bytes read from the file so far.  Reading bytes from this
    389      * stream will increment the channel's position.  Changing the channel's
    390      * position, either explicitly or by reading, will change this stream's
    391      * file position.
    392      *
    393      * @return  the file channel associated with this file input stream
    394      *
    395      * @since 1.4
    396      * @spec JSR-51
    397      */
    398     public FileChannel getChannel() {
    399         synchronized (this) {
    400             if (channel == null) {
    401                 channel = FileChannelImpl.open(fd, path, true, false, this);
    402 
    403             }
    404             return channel;
    405         }
    406     }
    407 
    408     /**
    409      * Ensures that the <code>close</code> method of this file input stream is
    410      * called when there are no more references to it.
    411      *
    412      * @exception  IOException  if an I/O error occurs.
    413      * @see        java.io.FileInputStream#close()
    414      */
    415     protected void finalize() throws IOException {
    416         if (guard != null) {
    417             guard.warnIfOpen();
    418         }
    419 
    420         if ((fd != null) &&  (fd != FileDescriptor.in)) {
    421             close();
    422         }
    423     }
    424 }
    425