001 /*
002 * Copyright 1994-2007 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package java.io;
027
028 import java.nio.channels.FileChannel;
029 import sun.nio.ch.FileChannelImpl;
030
031 /**
032 * A <code>FileInputStream</code> obtains input bytes
033 * from a file in a file system. What files
034 * are available depends on the host environment.
035 *
036 * <p><code>FileInputStream</code> is meant for reading streams of raw bytes
037 * such as image data. For reading streams of characters, consider using
038 * <code>FileReader</code>.
039 *
040 * @author Arthur van Hoff
041 * @version 1.78, 06/13/07
042 * @see java.io.File
043 * @see java.io.FileDescriptor
044 * @see java.io.FileOutputStream
045 * @since JDK1.0
046 */
047 public class FileInputStream extends InputStream {
048 /* File Descriptor - handle to the open file */
049 private FileDescriptor fd;
050
051 private FileChannel channel = null;
052
053 private Object closeLock = new Object();
054 private volatile boolean closed = false;
055
056 private static ThreadLocal<Boolean> runningFinalize = new ThreadLocal<Boolean>();
057
058 private static boolean isRunningFinalize() {
059 Boolean val;
060 if ((val = runningFinalize.get()) != null)
061 return val.booleanValue();
062 return false;
063 }
064
065 /**
066 * Creates a <code>FileInputStream</code> by
067 * opening a connection to an actual file,
068 * the file named by the path name <code>name</code>
069 * in the file system. A new <code>FileDescriptor</code>
070 * object is created to represent this file
071 * connection.
072 * <p>
073 * First, if there is a security
074 * manager, its <code>checkRead</code> method
075 * is called with the <code>name</code> argument
076 * as its argument.
077 * <p>
078 * If the named file does not exist, is a directory rather than a regular
079 * file, or for some other reason cannot be opened for reading then a
080 * <code>FileNotFoundException</code> is thrown.
081 *
082 * @param name the system-dependent file name.
083 * @exception FileNotFoundException if the file does not exist,
084 * is a directory rather than a regular file,
085 * or for some other reason cannot be opened for
086 * reading.
087 * @exception SecurityException if a security manager exists and its
088 * <code>checkRead</code> method denies read access
089 * to the file.
090 * @see java.lang.SecurityManager#checkRead(java.lang.String)
091 */
092 public FileInputStream(String name) throws FileNotFoundException {
093 this (name != null ? new File(name) : null);
094 }
095
096 /**
097 * Creates a <code>FileInputStream</code> by
098 * opening a connection to an actual file,
099 * the file named by the <code>File</code>
100 * object <code>file</code> in the file system.
101 * A new <code>FileDescriptor</code> object
102 * is created to represent this file connection.
103 * <p>
104 * First, if there is a security manager,
105 * its <code>checkRead</code> method is called
106 * with the path represented by the <code>file</code>
107 * argument as its argument.
108 * <p>
109 * If the named file does not exist, is a directory rather than a regular
110 * file, or for some other reason cannot be opened for reading then a
111 * <code>FileNotFoundException</code> is thrown.
112 *
113 * @param file the file to be opened for reading.
114 * @exception FileNotFoundException if the file does not exist,
115 * is a directory rather than a regular file,
116 * or for some other reason cannot be opened for
117 * reading.
118 * @exception SecurityException if a security manager exists and its
119 * <code>checkRead</code> method denies read access to the file.
120 * @see java.io.File#getPath()
121 * @see java.lang.SecurityManager#checkRead(java.lang.String)
122 */
123 public FileInputStream(File file) throws FileNotFoundException {
124 String name = (file != null ? file.getPath() : null);
125 SecurityManager security = System.getSecurityManager();
126 if (security != null) {
127 security.checkRead(name);
128 }
129 if (name == null) {
130 throw new NullPointerException();
131 }
132 fd = new FileDescriptor();
133 fd.incrementAndGetUseCount();
134 open(name);
135 }
136
137 /**
138 * Creates a <code>FileInputStream</code> by using the file descriptor
139 * <code>fdObj</code>, which represents an existing connection to an
140 * actual file in the file system.
141 * <p>
142 * If there is a security manager, its <code>checkRead</code> method is
143 * called with the file descriptor <code>fdObj</code> as its argument to
144 * see if it's ok to read the file descriptor. If read access is denied
145 * to the file descriptor a <code>SecurityException</code> is thrown.
146 * <p>
147 * If <code>fdObj</code> is null then a <code>NullPointerException</code>
148 * is thrown.
149 * <p>
150 * This constructor does not throw an exception if <code>fdObj</code>
151 * is {link java.io.FileDescriptor#valid() invalid}.
152 * However, if the methods are invoked on the resulting stream to attempt
153 * I/O on the stream, an <code>IOException</code> is thrown.
154 *
155 * @param fdObj the file descriptor to be opened for reading.
156 * @throws SecurityException if a security manager exists and its
157 * <code>checkRead</code> method denies read access to the
158 * file descriptor.
159 * @see SecurityManager#checkRead(java.io.FileDescriptor)
160 */
161 public FileInputStream(FileDescriptor fdObj) {
162 SecurityManager security = System.getSecurityManager();
163 if (fdObj == null) {
164 throw new NullPointerException();
165 }
166 if (security != null) {
167 security.checkRead(fdObj);
168 }
169 fd = fdObj;
170
171 /*
172 * FileDescriptor is being shared by streams.
173 * Ensure that it's GC'ed only when all the streams/channels are done
174 * using it.
175 */
176 fd.incrementAndGetUseCount();
177 }
178
179 /**
180 * Opens the specified file for reading.
181 * @param name the name of the file
182 */
183 private native void open(String name) throws FileNotFoundException;
184
185 /**
186 * Reads a byte of data from this input stream. This method blocks
187 * if no input is yet available.
188 *
189 * @return the next byte of data, or <code>-1</code> if the end of the
190 * file is reached.
191 * @exception IOException if an I/O error occurs.
192 */
193 public native int read() throws IOException;
194
195 /**
196 * Reads a subarray as a sequence of bytes.
197 * @param b the data to be written
198 * @param off the start offset in the data
199 * @param len the number of bytes that are written
200 * @exception IOException If an I/O error has occurred.
201 */
202 private native int readBytes(byte b[], int off, int len)
203 throws IOException;
204
205 /**
206 * Reads up to <code>b.length</code> bytes of data from this input
207 * stream into an array of bytes. This method blocks until some input
208 * is available.
209 *
210 * @param b the buffer into which the data is read.
211 * @return the total number of bytes read into the buffer, or
212 * <code>-1</code> if there is no more data because the end of
213 * the file has been reached.
214 * @exception IOException if an I/O error occurs.
215 */
216 public int read(byte b[]) throws IOException {
217 return readBytes(b, 0, b.length);
218 }
219
220 /**
221 * Reads up to <code>len</code> bytes of data from this input stream
222 * into an array of bytes. If <code>len</code> is not zero, the method
223 * blocks until some input is available; otherwise, no
224 * bytes are read and <code>0</code> is returned.
225 *
226 * @param b the buffer into which the data is read.
227 * @param off the start offset in the destination array <code>b</code>
228 * @param len the maximum number of bytes read.
229 * @return the total number of bytes read into the buffer, or
230 * <code>-1</code> if there is no more data because the end of
231 * the file has been reached.
232 * @exception NullPointerException If <code>b</code> is <code>null</code>.
233 * @exception IndexOutOfBoundsException If <code>off</code> is negative,
234 * <code>len</code> is negative, or <code>len</code> is greater than
235 * <code>b.length - off</code>
236 * @exception IOException if an I/O error occurs.
237 */
238 public int read(byte b[], int off, int len) throws IOException {
239 return readBytes(b, off, len);
240 }
241
242 /**
243 * Skips over and discards <code>n</code> bytes of data from the
244 * input stream.
245 *
246 * <p>The <code>skip</code> method may, for a variety of
247 * reasons, end up skipping over some smaller number of bytes,
248 * possibly <code>0</code>. If <code>n</code> is negative, an
249 * <code>IOException</code> is thrown, even though the <code>skip</code>
250 * method of the {@link InputStream} superclass does nothing in this case.
251 * The actual number of bytes skipped is returned.
252 *
253 * <p>This method may skip more bytes than are remaining in the backing
254 * file. This produces no exception and the number of bytes skipped
255 * may include some number of bytes that were beyond the EOF of the
256 * backing file. Attempting to read from the stream after skipping past
257 * the end will result in -1 indicating the end of the file.
258 *
259 * @param n the number of bytes to be skipped.
260 * @return the actual number of bytes skipped.
261 * @exception IOException if n is negative, if the stream does not
262 * support seek, or if an I/O error occurs.
263 */
264 public native long skip(long n) throws IOException;
265
266 /**
267 * Returns an estimate of the number of remaining bytes that can be read (or
268 * skipped over) from this input stream without blocking by the next
269 * invocation of a method for this input stream. The next invocation might be
270 * the same thread or another thread. A single read or skip of this
271 * many bytes will not block, but may read or skip fewer bytes.
272 *
273 * <p> In some cases, a non-blocking read (or skip) may appear to be
274 * blocked when it is merely slow, for example when reading large
275 * files over slow networks.
276 *
277 * @return an estimate of the number of remaining bytes that can be read
278 * (or skipped over) from this input stream without blocking.
279 * @exception IOException if this file input stream has been closed by calling
280 * {@code close} or an I/O error occurs.
281 */
282 public native int available() throws IOException;
283
284 /**
285 * Closes this file input stream and releases any system resources
286 * associated with the stream.
287 *
288 * <p> If this stream has an associated channel then the channel is closed
289 * as well.
290 *
291 * @exception IOException if an I/O error occurs.
292 *
293 * @revised 1.4
294 * @spec JSR-51
295 */
296 public void close() throws IOException {
297 synchronized (closeLock) {
298 if (closed) {
299 return;
300 }
301 closed = true;
302 }
303 if (channel != null) {
304 /*
305 * Decrement the FD use count associated with the channel
306 * The use count is incremented whenever a new channel
307 * is obtained from this stream.
308 */
309 fd.decrementAndGetUseCount();
310 channel.close();
311 }
312
313 /*
314 * Decrement the FD use count associated with this stream
315 */
316 int useCount = fd.decrementAndGetUseCount();
317
318 /*
319 * If FileDescriptor is still in use by another stream, the finalizer
320 * will not close it.
321 */
322 if ((useCount <= 0) || !isRunningFinalize()) {
323 close0();
324 }
325 }
326
327 /**
328 * Returns the <code>FileDescriptor</code>
329 * object that represents the connection to
330 * the actual file in the file system being
331 * used by this <code>FileInputStream</code>.
332 *
333 * @return the file descriptor object associated with this stream.
334 * @exception IOException if an I/O error occurs.
335 * @see java.io.FileDescriptor
336 */
337 public final FileDescriptor getFD() throws IOException {
338 if (fd != null)
339 return fd;
340 throw new IOException();
341 }
342
343 /**
344 * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
345 * object associated with this file input stream.
346 *
347 * <p> The initial {@link java.nio.channels.FileChannel#position()
348 * </code>position<code>} of the returned channel will be equal to the
349 * number of bytes read from the file so far. Reading bytes from this
350 * stream will increment the channel's position. Changing the channel's
351 * position, either explicitly or by reading, will change this stream's
352 * file position.
353 *
354 * @return the file channel associated with this file input stream
355 *
356 * @since 1.4
357 * @spec JSR-51
358 */
359 public FileChannel getChannel() {
360 synchronized (this ) {
361 if (channel == null) {
362 channel = FileChannelImpl.open(fd, true, false, this );
363
364 /*
365 * Increment fd's use count. Invoking the channel's close()
366 * method will result in decrementing the use count set for
367 * the channel.
368 */
369 fd.incrementAndGetUseCount();
370 }
371 return channel;
372 }
373 }
374
375 private static native void initIDs();
376
377 private native void close0() throws IOException;
378
379 static {
380 initIDs();
381 }
382
383 /**
384 * Ensures that the <code>close</code> method of this file input stream is
385 * called when there are no more references to it.
386 *
387 * @exception IOException if an I/O error occurs.
388 * @see java.io.FileInputStream#close()
389 */
390 protected void finalize() throws IOException {
391 if ((fd != null) && (fd != fd.in)) {
392
393 /*
394 * Finalizer should not release the FileDescriptor if another
395 * stream is still using it. If the user directly invokes
396 * close() then the FileDescriptor is also released.
397 */
398 runningFinalize.set(Boolean.TRUE);
399 try {
400 close();
401 } finally {
402 runningFinalize.set(Boolean.FALSE);
403 }
404 }
405 }
406 }
|