FileInputStream.java revision 2c87ad3a45cecf9e344487cad1abfdebe79f2c7c
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
27package java.io;
28
29import java.nio.channels.FileChannel;
30import sun.nio.ch.FileChannelImpl;
31import sun.misc.IoTrace;
32import libcore.io.IoBridge;
33
34
35/**
36 * A <code>FileInputStream</code> obtains input bytes
37 * from a file in a file system. What files
38 * are  available depends on the host environment.
39 *
40 * <p><code>FileInputStream</code> is meant for reading streams of raw bytes
41 * such as image data. For reading streams of characters, consider using
42 * <code>FileReader</code>.
43 *
44 * @author  Arthur van Hoff
45 * @see     java.io.File
46 * @see     java.io.FileDescriptor
47 * @see     java.io.FileOutputStream
48 * @see     java.nio.file.Files#newInputStream
49 * @since   JDK1.0
50 */
51public
52class FileInputStream extends InputStream
53{
54    /* File Descriptor - handle to the open file */
55    private final FileDescriptor fd;
56
57    /* The path of the referenced file (null if the stream is created with a file descriptor) */
58    private final String path;
59
60    private FileChannel channel = null;
61
62    private final Object closeLock = new Object();
63    private volatile boolean closed = false;
64
65    private static final ThreadLocal<Boolean> runningFinalize =
66        new ThreadLocal<>();
67
68    private static boolean isRunningFinalize() {
69        Boolean val;
70        if ((val = runningFinalize.get()) != null)
71            return val.booleanValue();
72        return false;
73    }
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        fd.incrementAndGetUseCount();
147        this.path = name;
148        open(name);
149    }
150
151    /**
152     * Creates a <code>FileInputStream</code> by using the file descriptor
153     * <code>fdObj</code>, which represents an existing connection to an
154     * actual file in the file system.
155     * <p>
156     * If there is a security manager, its <code>checkRead</code> method is
157     * called with the file descriptor <code>fdObj</code> as its argument to
158     * see if it's ok to read the file descriptor. If read access is denied
159     * to the file descriptor a <code>SecurityException</code> is thrown.
160     * <p>
161     * If <code>fdObj</code> is null then a <code>NullPointerException</code>
162     * is thrown.
163     * <p>
164     * This constructor does not throw an exception if <code>fdObj</code>
165     * is {@link java.io.FileDescriptor#valid() invalid}.
166     * However, if the methods are invoked on the resulting stream to attempt
167     * I/O on the stream, an <code>IOException</code> is thrown.
168     *
169     * @param      fdObj   the file descriptor to be opened for reading.
170     * @throws     SecurityException      if a security manager exists and its
171     *                 <code>checkRead</code> method denies read access to the
172     *                 file descriptor.
173     * @see        SecurityManager#checkRead(java.io.FileDescriptor)
174     */
175    public FileInputStream(FileDescriptor fdObj) {
176        SecurityManager security = System.getSecurityManager();
177        if (fdObj == null) {
178            throw new NullPointerException();
179        }
180        if (security != null) {
181            security.checkRead(fdObj);
182        }
183        fd = fdObj;
184        path = null;
185
186        /*
187         * FileDescriptor is being shared by streams.
188         * Ensure that it's GC'ed only when all the streams/channels are done
189         * using it.
190         */
191        fd.incrementAndGetUseCount();
192    }
193
194    /**
195     * Opens the specified file for reading.
196     * @param name the name of the file
197     */
198    private native void open(String name) throws FileNotFoundException;
199
200    /**
201     * Reads a byte of data from this input stream. This method blocks
202     * if no input is yet available.
203     *
204     * @return     the next byte of data, or <code>-1</code> if the end of the
205     *             file is reached.
206     * @exception  IOException  if an I/O error occurs.
207     */
208    public int read() throws IOException {
209        Object traceContext = IoTrace.fileReadBegin(path);
210
211        /* ----- BEGIN android -----
212        int b = 0;
213        try {
214            b = read0();
215        } finally {
216            IoTrace.fileReadEnd(traceContext, b == -1 ? 0 : 1);
217        }
218        return b;*/
219        byte[] b = new byte[1];
220        int res = -1;
221        try {
222            res = read(b, 0, 1);
223        } finally {
224            IoTrace.fileReadEnd(traceContext, res);
225        }
226        return (res != -1) ? b[0] & 0xff : -1;
227        // ----- END android -----
228    }
229
230    /* ----- BEGIN android -----
231    private native int read0() throws IOException;
232    ----- END android -----*/
233
234    /**
235     * Reads a subarray as a sequence of bytes.
236     * @param b the data to be written
237     * @param off the start offset in the data
238     * @param len the number of bytes that are written
239     * @exception IOException If an I/O error has occurred.
240     */
241    /* ----- BEGIN android -----
242    private native int readBytes(byte b[], int off, int len) throws IOException;
243    ----- END android -----*/
244
245    /**
246     * Reads up to <code>b.length</code> bytes of data from this input
247     * stream into an array of bytes. This method blocks until some input
248     * is available.
249     *
250     * @param      b   the buffer into which the data is read.
251     * @return     the total number of bytes read into the buffer, or
252     *             <code>-1</code> if there is no more data because the end of
253     *             the file has been reached.
254     * @exception  IOException  if an I/O error occurs.
255     */
256    public int read(byte b[]) throws IOException {
257        /* ----- BEGIN android -----
258        Object traceContext = IoTrace.fileReadBegin(path);
259        int bytesRead = 0;
260        try {
261            bytesRead = readBytes(b, 0, b.length);
262        } finally {
263            IoTrace.fileReadEnd(traceContext, bytesRead == -1 ? 0 : bytesRead);
264        }
265        return bytesRead;*/
266        return read(b, 0, b.length);
267    }
268
269    /**
270     * Reads up to <code>len</code> bytes of data from this input stream
271     * into an array of bytes. If <code>len</code> is not zero, the method
272     * blocks until some input is available; otherwise, no
273     * bytes are read and <code>0</code> is returned.
274     *
275     * @param      b     the buffer into which the data is read.
276     * @param      off   the start offset in the destination array <code>b</code>
277     * @param      len   the maximum number of bytes read.
278     * @return     the total number of bytes read into the buffer, or
279     *             <code>-1</code> if there is no more data because the end of
280     *             the file has been reached.
281     * @exception  NullPointerException If <code>b</code> is <code>null</code>.
282     * @exception  IndexOutOfBoundsException If <code>off</code> is negative,
283     * <code>len</code> is negative, or <code>len</code> is greater than
284     * <code>b.length - off</code>
285     * @exception  IOException  if an I/O error occurs.
286     */
287    public int read(byte b[], int off, int len) throws IOException {
288        if (closed && len > 0) {
289            throw new IOException("Stream Closed");
290        }
291
292        Object traceContext = IoTrace.fileReadBegin(path);
293        int bytesRead = 0;
294        try {
295            /* ----- BEGIN android -----
296            bytesRead = readBytes(b, off, len);*/
297            bytesRead = IoBridge.read(fd, b, off, len);
298            // ----- END android -----
299        } finally {
300            IoTrace.fileReadEnd(traceContext, bytesRead == -1 ? 0 : bytesRead);
301        }
302        return bytesRead;
303    }
304
305    /**
306     * Skips over and discards <code>n</code> bytes of data from the
307     * input stream.
308     *
309     * <p>The <code>skip</code> method may, for a variety of
310     * reasons, end up skipping over some smaller number of bytes,
311     * possibly <code>0</code>. If <code>n</code> is negative, an
312     * <code>IOException</code> is thrown, even though the <code>skip</code>
313     * method of the {@link InputStream} superclass does nothing in this case.
314     * The actual number of bytes skipped is returned.
315     *
316     * <p>This method may skip more bytes than are remaining in the backing
317     * file. This produces no exception and the number of bytes skipped
318     * may include some number of bytes that were beyond the EOF of the
319     * backing file. Attempting to read from the stream after skipping past
320     * the end will result in -1 indicating the end of the file.
321     *
322     * @param      n   the number of bytes to be skipped.
323     * @return     the actual number of bytes skipped.
324     * @exception  IOException  if n is negative, if the stream does not
325     *             support seek, or if an I/O error occurs.
326     */
327    public long skip(long n) throws IOException {
328      if (closed) {
329        throw new IOException("Stream Closed");
330      }
331
332      try {
333        return skip0(n);
334      } catch(UseManualSkipException e) {
335        return super.skip(n);
336      }
337    }
338
339    private native long skip0(long n) throws IOException, UseManualSkipException;
340
341    /*
342     * Used to force manual skip when FileInputStream operates on pipe
343     */
344    private static class UseManualSkipException extends Exception {
345    }
346
347    /**
348     * Returns an estimate of the number of remaining bytes that can be read (or
349     * skipped over) from this input stream without blocking by the next
350     * invocation of a method for this input stream. The next invocation might be
351     * the same thread or another thread.  A single read or skip of this
352     * many bytes will not block, but may read or skip fewer bytes.
353     *
354     * <p> In some cases, a non-blocking read (or skip) may appear to be
355     * blocked when it is merely slow, for example when reading large
356     * files over slow networks.
357     *
358     * @return     an estimate of the number of remaining bytes that can be read
359     *             (or skipped over) from this input stream without blocking.
360     * @exception  IOException  if this file input stream has been closed by calling
361     *             {@code close} or an I/O error occurs.
362     */
363    public int available() throws IOException {
364        if (closed) {
365            throw new IOException("Stream Closed");
366        }
367
368        return available0();
369    }
370
371    private native int available0() throws IOException;
372
373    /**
374     * Closes this file input stream and releases any system resources
375     * associated with the stream.
376     *
377     * <p> If this stream has an associated channel then the channel is closed
378     * as well.
379     *
380     * @exception  IOException  if an I/O error occurs.
381     *
382     * @revised 1.4
383     * @spec JSR-51
384     */
385    public void close() throws IOException {
386        synchronized (closeLock) {
387            if (closed) {
388                return;
389            }
390            closed = true;
391        }
392        if (channel != null) {
393            /*
394             * Decrement the FD use count associated with the channel
395             * The use count is incremented whenever a new channel
396             * is obtained from this stream.
397             */
398           fd.decrementAndGetUseCount();
399           channel.close();
400        }
401
402        /*
403         * Decrement the FD use count associated with this stream
404         */
405        int useCount = fd.decrementAndGetUseCount();
406
407        /*
408         * If FileDescriptor is still in use by another stream, the finalizer
409         * will not close it.
410         */
411        // Android change, make sure only last close closes FD.
412        if ((useCount <= 0)) { //  || !isRunningFinalize()) {
413            /* ----- BEGIN android -----
414               close0(); */
415            IoBridge.closeAndSignalBlockedThreads(fd);
416            // ----- END android -----
417        }
418    }
419
420    /**
421     * Returns the <code>FileDescriptor</code>
422     * object  that represents the connection to
423     * the actual file in the file system being
424     * used by this <code>FileInputStream</code>.
425     *
426     * @return     the file descriptor object associated with this stream.
427     * @exception  IOException  if an I/O error occurs.
428     * @see        java.io.FileDescriptor
429     */
430    public final FileDescriptor getFD() throws IOException {
431        if (fd != null) return fd;
432        throw new IOException();
433    }
434
435    /**
436     * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
437     * object associated with this file input stream.
438     *
439     * <p> The initial {@link java.nio.channels.FileChannel#position()
440     * </code>position<code>} of the returned channel will be equal to the
441     * number of bytes read from the file so far.  Reading bytes from this
442     * stream will increment the channel's position.  Changing the channel's
443     * position, either explicitly or by reading, will change this stream's
444     * file position.
445     *
446     * @return  the file channel associated with this file input stream
447     *
448     * @since 1.4
449     * @spec JSR-51
450     */
451    public FileChannel getChannel() {
452        synchronized (this) {
453            if (channel == null) {
454                channel = FileChannelImpl.open(fd, path, true, false, this);
455
456                /*
457                 * Increment fd's use count. Invoking the channel's close()
458                 * method will result in decrementing the use count set for
459                 * the channel.
460                 */
461                fd.incrementAndGetUseCount();
462            }
463            return channel;
464        }
465    }
466
467    private static native void initIDs();
468
469    private native void close0() throws IOException;
470
471    static {
472        initIDs();
473    }
474
475    /**
476     * Ensures that the <code>close</code> method of this file input stream is
477     * called when there are no more references to it.
478     *
479     * @exception  IOException  if an I/O error occurs.
480     * @see        java.io.FileInputStream#close()
481     */
482    protected void finalize() throws IOException {
483        if ((fd != null) &&  (fd != FileDescriptor.in)) {
484
485            /*
486             * Finalizer should not release the FileDescriptor if another
487             * stream is still using it. If the user directly invokes
488             * close() then the FileDescriptor is also released.
489             */
490            runningFinalize.set(Boolean.TRUE);
491            try {
492                close();
493            } finally {
494                runningFinalize.set(Boolean.FALSE);
495            }
496        }
497    }
498}
499