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: }
|