FileInputStream.java revision 5873edf853a48362e8ee4e75181f654d0b88b8ef
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;
30
31import dalvik.system.BlockGuard;
32import sun.nio.ch.FileChannelImpl;
33import sun.misc.IoTrace;
34import libcore.io.IoBridge;
35
36
37/**
38 * A <code>FileInputStream</code> obtains input bytes
39 * from a file in a file system. What files
40 * are  available depends on the host environment.
41 *
42 * <p><code>FileInputStream</code> is meant for reading streams of raw bytes
43 * such as image data. For reading streams of characters, consider using
44 * <code>FileReader</code>.
45 *
46 * @author  Arthur van Hoff
47 * @see     java.io.File
48 * @see     java.io.FileDescriptor
49 * @see     java.io.FileOutputStream
50 * @see     java.nio.file.Files#newInputStream
51 * @since   JDK1.0
52 */
53public
54class FileInputStream extends InputStream
55{
56    /* File Descriptor - handle to the open file */
57    private final FileDescriptor fd;
58
59    /* The path of the referenced file (null if the stream is created with a file descriptor) */
60    private final String path;
61
62    private FileChannel channel = null;
63
64    private final Object closeLock = new Object();
65    private volatile boolean closed = false;
66
67    /**
68     * Creates a <code>FileInputStream</code> by
69     * opening a connection to an actual file,
70     * the file named by the path name <code>name</code>
71     * in the file system.  A new <code>FileDescriptor</code>
72     * object is created to represent this file
73     * connection.
74     * <p>
75     * First, if there is a security
76     * manager, its <code>checkRead</code> method
77     * is called with the <code>name</code> argument
78     * as its argument.
79     * <p>
80     * If the named file does not exist, is a directory rather than a regular
81     * file, or for some other reason cannot be opened for reading then a
82     * <code>FileNotFoundException</code> is thrown.
83     *
84     * @param      name   the system-dependent file name.
85     * @exception  FileNotFoundException  if the file does not exist,
86     *                   is a directory rather than a regular file,
87     *                   or for some other reason cannot be opened for
88     *                   reading.
89     * @exception  SecurityException      if a security manager exists and its
90     *               <code>checkRead</code> method denies read access
91     *               to the file.
92     * @see        java.lang.SecurityManager#checkRead(java.lang.String)
93     */
94    public FileInputStream(String name) throws FileNotFoundException {
95        this(name != null ? new File(name) : null);
96    }
97
98    /**
99     * Creates a <code>FileInputStream</code> by
100     * opening a connection to an actual file,
101     * the file named by the <code>File</code>
102     * object <code>file</code> in the file system.
103     * A new <code>FileDescriptor</code> object
104     * is created to represent this file connection.
105     * <p>
106     * First, if there is a security manager,
107     * its <code>checkRead</code> method  is called
108     * with the path represented by the <code>file</code>
109     * argument as its argument.
110     * <p>
111     * If the named file does not exist, is a directory rather than a regular
112     * file, or for some other reason cannot be opened for reading then a
113     * <code>FileNotFoundException</code> is thrown.
114     *
115     * @param      file   the file to be opened for reading.
116     * @exception  FileNotFoundException  if the file does not exist,
117     *                   is a directory rather than a regular file,
118     *                   or for some other reason cannot be opened for
119     *                   reading.
120     * @exception  SecurityException      if a security manager exists and its
121     *               <code>checkRead</code> method denies read access to the file.
122     * @see        java.io.File#getPath()
123     * @see        java.lang.SecurityManager#checkRead(java.lang.String)
124     */
125    public FileInputStream(File file) throws FileNotFoundException {
126        String name = (file != null ? file.getPath() : null);
127        SecurityManager security = System.getSecurityManager();
128        if (security != null) {
129            security.checkRead(name);
130        }
131        if (name == null) {
132            throw new NullPointerException();
133        }
134        if (file.isInvalid()) {
135            throw new FileNotFoundException("Invalid file path");
136        }
137        fd = new FileDescriptor();
138        fd.incrementAndGetUseCount();
139        this.path = name;
140
141        BlockGuard.getThreadPolicy().onReadFromDisk();
142        open(name);
143    }
144
145    /**
146     * Creates a <code>FileInputStream</code> by using the file descriptor
147     * <code>fdObj</code>, which represents an existing connection to an
148     * actual file in the file system.
149     * <p>
150     * If there is a security manager, its <code>checkRead</code> method is
151     * called with the file descriptor <code>fdObj</code> as its argument to
152     * see if it's ok to read the file descriptor. If read access is denied
153     * to the file descriptor a <code>SecurityException</code> is thrown.
154     * <p>
155     * If <code>fdObj</code> is null then a <code>NullPointerException</code>
156     * is thrown.
157     * <p>
158     * This constructor does not throw an exception if <code>fdObj</code>
159     * is {@link java.io.FileDescriptor#valid() invalid}.
160     * However, if the methods are invoked on the resulting stream to attempt
161     * I/O on the stream, an <code>IOException</code> is thrown.
162     *
163     * @param      fdObj   the file descriptor to be opened for reading.
164     * @throws     SecurityException      if a security manager exists and its
165     *                 <code>checkRead</code> method denies read access to the
166     *                 file descriptor.
167     * @see        SecurityManager#checkRead(java.io.FileDescriptor)
168     */
169    public FileInputStream(FileDescriptor fdObj) {
170        SecurityManager security = System.getSecurityManager();
171        if (fdObj == null) {
172            throw new NullPointerException();
173        }
174        if (security != null) {
175            security.checkRead(fdObj);
176        }
177        fd = fdObj;
178        path = null;
179
180        /*
181         * FileDescriptor is being shared by streams.
182         * Ensure that it's GC'ed only when all the streams/channels are done
183         * using it.
184         */
185        fd.incrementAndGetUseCount();
186    }
187
188    /**
189     * Opens the specified file for reading.
190     * @param name the name of the file
191     */
192    private native void open(String name) throws FileNotFoundException;
193
194    /**
195     * Reads a byte of data from this input stream. This method blocks
196     * if no input is yet available.
197     *
198     * @return     the next byte of data, or <code>-1</code> if the end of the
199     *             file is reached.
200     * @exception  IOException  if an I/O error occurs.
201     */
202    public int read() throws IOException {
203        Object traceContext = IoTrace.fileReadBegin(path);
204
205        byte[] b = new byte[1];
206        int res = -1;
207        try {
208            res = read(b, 0, 1);
209        } finally {
210            IoTrace.fileReadEnd(traceContext, res);
211        }
212        return (res != -1) ? b[0] & 0xff : -1;
213    }
214
215    /**
216     * Reads up to <code>b.length</code> bytes of data from this input
217     * stream into an array of bytes. This method blocks until some input
218     * is available.
219     *
220     * @param      b   the buffer into which the data is read.
221     * @return     the total number of bytes read into the buffer, or
222     *             <code>-1</code> if there is no more data because the end of
223     *             the file has been reached.
224     * @exception  IOException  if an I/O error occurs.
225     */
226    public int read(byte b[]) throws IOException {
227        return read(b, 0, b.length);
228    }
229
230    /**
231     * Reads up to <code>len</code> bytes of data from this input stream
232     * into an array of bytes. If <code>len</code> is not zero, the method
233     * blocks until some input is available; otherwise, no
234     * bytes are read and <code>0</code> is returned.
235     *
236     * @param      b     the buffer into which the data is read.
237     * @param      off   the start offset in the destination array <code>b</code>
238     * @param      len   the maximum number of bytes read.
239     * @return     the total number of bytes read into the buffer, or
240     *             <code>-1</code> if there is no more data because the end of
241     *             the file has been reached.
242     * @exception  NullPointerException If <code>b</code> is <code>null</code>.
243     * @exception  IndexOutOfBoundsException If <code>off</code> is negative,
244     * <code>len</code> is negative, or <code>len</code> is greater than
245     * <code>b.length - off</code>
246     * @exception  IOException  if an I/O error occurs.
247     */
248    public int read(byte b[], int off, int len) throws IOException {
249        if (closed && len > 0) {
250            throw new IOException("Stream Closed");
251        }
252
253        Object traceContext = IoTrace.fileReadBegin(path);
254        int bytesRead = 0;
255        try {
256            bytesRead = IoBridge.read(fd, b, off, len);
257        } finally {
258            IoTrace.fileReadEnd(traceContext, bytesRead == -1 ? 0 : bytesRead);
259        }
260        return bytesRead;
261    }
262
263    /**
264     * Skips over and discards <code>n</code> bytes of data from the
265     * input stream.
266     *
267     * <p>The <code>skip</code> method may, for a variety of
268     * reasons, end up skipping over some smaller number of bytes,
269     * possibly <code>0</code>. If <code>n</code> is negative, an
270     * <code>IOException</code> is thrown, even though the <code>skip</code>
271     * method of the {@link InputStream} superclass does nothing in this case.
272     * The actual number of bytes skipped is returned.
273     *
274     * <p>This method may skip more bytes than are remaining in the backing
275     * file. This produces no exception and the number of bytes skipped
276     * may include some number of bytes that were beyond the EOF of the
277     * backing file. Attempting to read from the stream after skipping past
278     * the end will result in -1 indicating the end of the file.
279     *
280     * @param      n   the number of bytes to be skipped.
281     * @return     the actual number of bytes skipped.
282     * @exception  IOException  if n is negative, if the stream does not
283     *             support seek, or if an I/O error occurs.
284     */
285    public long skip(long n) throws IOException {
286        if (closed) {
287            throw new IOException("Stream Closed");
288        }
289
290        try {
291            BlockGuard.getThreadPolicy().onReadFromDisk();
292            return skip0(n);
293        } catch(UseManualSkipException e) {
294            return super.skip(n);
295        }
296    }
297
298    private native long skip0(long n) throws IOException, UseManualSkipException;
299
300    /*
301     * Used to force manual skip when FileInputStream operates on pipe
302     */
303    private static class UseManualSkipException extends Exception {
304    }
305
306    /**
307     * Returns an estimate of the number of remaining bytes that can be read (or
308     * skipped over) from this input stream without blocking by the next
309     * invocation of a method for this input stream. The next invocation might be
310     * the same thread or another thread.  A single read or skip of this
311     * many bytes will not block, but may read or skip fewer bytes.
312     *
313     * <p> In some cases, a non-blocking read (or skip) may appear to be
314     * blocked when it is merely slow, for example when reading large
315     * files over slow networks.
316     *
317     * @return     an estimate of the number of remaining bytes that can be read
318     *             (or skipped over) from this input stream without blocking.
319     * @exception  IOException  if this file input stream has been closed by calling
320     *             {@code close} or an I/O error occurs.
321     */
322    public int available() throws IOException {
323        if (closed) {
324            throw new IOException("Stream Closed");
325        }
326
327        return available0();
328    }
329
330    private native int available0() throws IOException;
331
332    /**
333     * Closes this file input stream and releases any system resources
334     * associated with the stream.
335     *
336     * <p> If this stream has an associated channel then the channel is closed
337     * as well.
338     *
339     * @exception  IOException  if an I/O error occurs.
340     *
341     * @revised 1.4
342     * @spec JSR-51
343     */
344    public void close() throws IOException {
345        synchronized (closeLock) {
346            if (closed) {
347                return;
348            }
349            closed = true;
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           fd.decrementAndGetUseCount();
358           channel.close();
359        }
360
361        /*
362         * Decrement the FD use count associated with this stream
363         */
364        int useCount = fd.decrementAndGetUseCount();
365
366        /*
367         * If FileDescriptor is still in use by another stream, the finalizer
368         * will not close it.
369         */
370        // Android change, make sure only last close closes FD.
371        if ((useCount <= 0)) {
372            IoBridge.closeAndSignalBlockedThreads(fd);
373        }
374    }
375
376    /**
377     * Returns the <code>FileDescriptor</code>
378     * object  that represents the connection to
379     * the actual file in the file system being
380     * used by this <code>FileInputStream</code>.
381     *
382     * @return     the file descriptor object associated with this stream.
383     * @exception  IOException  if an I/O error occurs.
384     * @see        java.io.FileDescriptor
385     */
386    public final FileDescriptor getFD() throws IOException {
387        if (fd != null) return fd;
388        throw new IOException();
389    }
390
391    /**
392     * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
393     * object associated with this file input stream.
394     *
395     * <p> The initial {@link java.nio.channels.FileChannel#position()
396     * </code>position<code>} of the returned channel will be equal to the
397     * number of bytes read from the file so far.  Reading bytes from this
398     * stream will increment the channel's position.  Changing the channel's
399     * position, either explicitly or by reading, will change this stream's
400     * file position.
401     *
402     * @return  the file channel associated with this file input stream
403     *
404     * @since 1.4
405     * @spec JSR-51
406     */
407    public FileChannel getChannel() {
408        synchronized (this) {
409            if (channel == null) {
410                channel = FileChannelImpl.open(fd, path, true, false, this);
411
412                /*
413                 * Increment fd's use count. Invoking the channel's close()
414                 * method will result in decrementing the use count set for
415                 * the channel.
416                 */
417                fd.incrementAndGetUseCount();
418            }
419            return channel;
420        }
421    }
422
423    private static native void initIDs();
424
425    static {
426        initIDs();
427    }
428
429    /**
430     * Ensures that the <code>close</code> method of this file input stream is
431     * called when there are no more references to it.
432     *
433     * @exception  IOException  if an I/O error occurs.
434     * @see        java.io.FileInputStream#close()
435     */
436    protected void finalize() throws IOException {
437        if ((fd != null) &&  (fd != FileDescriptor.in)) {
438            close();
439        }
440    }
441}
442