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