• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */
17 
18 package java.io;
19 
20 import dalvik.system.CloseGuard;
21 
22 import android.system.ErrnoException;
23 import java.nio.channels.FileChannel;
24 import java.nio.NioUtils;
25 import libcore.io.IoBridge;
26 import libcore.io.Libcore;
27 import libcore.io.Streams;
28 import static android.system.OsConstants.*;
29 
30 /**
31  * An input stream that reads bytes from a file.
32  * <pre>   {@code
33  *   File file = ...
34  *   InputStream in = null;
35  *   try {
36  *     in = new BufferedInputStream(new FileInputStream(file));
37  *     ...
38  *   } finally {
39  *     if (in != null) {
40  *       in.close();
41  *     }
42  *   }
43  * }</pre>
44  *
45  * <p>This stream is <strong>not buffered</strong>. Most callers should wrap
46  * this stream with a {@link BufferedInputStream}.
47  *
48  * <p>Use {@link FileReader} to read characters, as opposed to bytes, from a
49  * file.
50  *
51  * @see BufferedInputStream
52  * @see FileOutputStream
53  */
54 public class FileInputStream extends InputStream {
55 
56     private FileDescriptor fd;
57     private final boolean shouldClose;
58 
59     /** The unique file channel. Lazily initialized because it's rarely needed. */
60     private FileChannel channel;
61 
62     private final CloseGuard guard = CloseGuard.get();
63 
64     /**
65      * Constructs a new {@code FileInputStream} that reads from {@code file}.
66      *
67      * @param file
68      *            the file from which this stream reads.
69      * @throws FileNotFoundException
70      *             if {@code file} does not exist.
71      */
FileInputStream(File file)72     public FileInputStream(File file) throws FileNotFoundException {
73         if (file == null) {
74             throw new NullPointerException("file == null");
75         }
76         this.fd = IoBridge.open(file.getPath(), O_RDONLY);
77         this.shouldClose = true;
78         guard.open("close");
79     }
80 
81     /**
82      * Constructs a new {@code FileInputStream} that reads from {@code fd}.
83      *
84      * @param fd
85      *            the FileDescriptor from which this stream reads.
86      * @throws NullPointerException
87      *             if {@code fd} is {@code null}.
88      */
FileInputStream(FileDescriptor fd)89     public FileInputStream(FileDescriptor fd) {
90         if (fd == null) {
91             throw new NullPointerException("fd == null");
92         }
93         this.fd = fd;
94         this.shouldClose = false;
95         // Note that we do not call guard.open here because the
96         // FileDescriptor is not owned by the stream.
97     }
98 
99     /**
100      * Equivalent to {@code new FileInputStream(new File(path))}.
101      */
FileInputStream(String path)102     public FileInputStream(String path) throws FileNotFoundException {
103         this(new File(path));
104     }
105 
106     @Override
available()107     public int available() throws IOException {
108         return IoBridge.available(fd);
109     }
110 
111     @Override
close()112     public void close() throws IOException {
113         guard.close();
114         synchronized (this) {
115             if (channel != null) {
116                 channel.close();
117             }
118             if (shouldClose) {
119                 IoBridge.closeAndSignalBlockedThreads(fd);
120             } else {
121                 // An owned fd has been invalidated by IoUtils.close, but
122                 // we need to explicitly stop using an unowned fd (http://b/4361076).
123                 fd = new FileDescriptor();
124             }
125         }
126     }
127 
128     /**
129      * Ensures that all resources for this stream are released when it is about
130      * to be garbage collected.
131      *
132      * @throws IOException
133      *             if an error occurs attempting to finalize this stream.
134      */
finalize()135     @Override protected void finalize() throws IOException {
136         try {
137             if (guard != null) {
138                 guard.warnIfOpen();
139             }
140             close();
141         } finally {
142             try {
143                 super.finalize();
144             } catch (Throwable t) {
145                 // for consistency with the RI, we must override Object.finalize() to
146                 // remove the 'throws Throwable' clause.
147                 throw new AssertionError(t);
148             }
149         }
150     }
151 
152     /**
153      * Returns a read-only {@link FileChannel} that shares its position with
154      * this stream.
155      */
getChannel()156     public FileChannel getChannel() {
157         synchronized (this) {
158             if (channel == null) {
159                 channel = NioUtils.newFileChannel(this, fd, O_RDONLY);
160             }
161             return channel;
162         }
163     }
164 
165     /**
166      * Returns the underlying file descriptor.
167      */
getFD()168     public final FileDescriptor getFD() throws IOException {
169         return fd;
170     }
171 
read()172     @Override public int read() throws IOException {
173         return Streams.readSingleByte(this);
174     }
175 
read(byte[] buffer, int byteOffset, int byteCount)176     @Override public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException {
177         return IoBridge.read(fd, buffer, byteOffset, byteCount);
178     }
179 
180     @Override
skip(long byteCount)181     public long skip(long byteCount) throws IOException {
182         if (byteCount < 0) {
183             throw new IOException("byteCount < 0: " + byteCount);
184         }
185         try {
186             // Try lseek(2). That returns the new offset, but we'll throw an
187             // exception if it couldn't perform exactly the seek we asked for.
188             Libcore.os.lseek(fd, byteCount, SEEK_CUR);
189             return byteCount;
190         } catch (ErrnoException errnoException) {
191             if (errnoException.errno == ESPIPE) {
192                 // You can't seek on a pipe, so fall back to the superclass' implementation.
193                 return super.skip(byteCount);
194             }
195             throw errnoException.rethrowAsIOException();
196         }
197     }
198 }
199