FileInputStream.java revision 51b1b6997fd3f980076b8081f7f1165ccc2a4008
1/* 2 * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package java.io; 27 28import java.nio.channels.FileChannel; 29import sun.nio.ch.FileChannelImpl; 30import sun.misc.IoTrace; 31 32 33/** 34 * A <code>FileInputStream</code> obtains input bytes 35 * from a file in a file system. What files 36 * are available depends on the host environment. 37 * 38 * <p><code>FileInputStream</code> is meant for reading streams of raw bytes 39 * such as image data. For reading streams of characters, consider using 40 * <code>FileReader</code>. 41 * 42 * @author Arthur van Hoff 43 * @see java.io.File 44 * @see java.io.FileDescriptor 45 * @see java.io.FileOutputStream 46 * @see java.nio.file.Files#newInputStream 47 * @since JDK1.0 48 */ 49public 50class FileInputStream extends InputStream 51{ 52 /* File Descriptor - handle to the open file */ 53 private final FileDescriptor fd; 54 55 /* The path of the referenced file (null if the stream is created with a file descriptor) */ 56 private final String path; 57 58 private FileChannel channel = null; 59 60 private final Object closeLock = new Object(); 61 private volatile boolean closed = false; 62 63 private static final ThreadLocal<Boolean> runningFinalize = 64 new ThreadLocal<>(); 65 66 private static boolean isRunningFinalize() { 67 Boolean val; 68 if ((val = runningFinalize.get()) != null) 69 return val.booleanValue(); 70 return false; 71 } 72 73 /** 74 * Creates a <code>FileInputStream</code> by 75 * opening a connection to an actual file, 76 * the file named by the path name <code>name</code> 77 * in the file system. A new <code>FileDescriptor</code> 78 * object is created to represent this file 79 * connection. 80 * <p> 81 * First, if there is a security 82 * manager, its <code>checkRead</code> method 83 * is called with the <code>name</code> argument 84 * as its argument. 85 * <p> 86 * If the named file does not exist, is a directory rather than a regular 87 * file, or for some other reason cannot be opened for reading then a 88 * <code>FileNotFoundException</code> is thrown. 89 * 90 * @param name the system-dependent file name. 91 * @exception FileNotFoundException if the file does not exist, 92 * is a directory rather than a regular file, 93 * or for some other reason cannot be opened for 94 * reading. 95 * @exception SecurityException if a security manager exists and its 96 * <code>checkRead</code> method denies read access 97 * to the file. 98 * @see java.lang.SecurityManager#checkRead(java.lang.String) 99 */ 100 public FileInputStream(String name) throws FileNotFoundException { 101 this(name != null ? new File(name) : null); 102 } 103 104 /** 105 * Creates a <code>FileInputStream</code> by 106 * opening a connection to an actual file, 107 * the file named by the <code>File</code> 108 * object <code>file</code> in the file system. 109 * A new <code>FileDescriptor</code> object 110 * is created to represent this file connection. 111 * <p> 112 * First, if there is a security manager, 113 * its <code>checkRead</code> method is called 114 * with the path represented by the <code>file</code> 115 * argument as its argument. 116 * <p> 117 * If the named file does not exist, is a directory rather than a regular 118 * file, or for some other reason cannot be opened for reading then a 119 * <code>FileNotFoundException</code> is thrown. 120 * 121 * @param file the file to be opened for reading. 122 * @exception FileNotFoundException if the file does not exist, 123 * is a directory rather than a regular file, 124 * or for some other reason cannot be opened for 125 * reading. 126 * @exception SecurityException if a security manager exists and its 127 * <code>checkRead</code> method denies read access to the file. 128 * @see java.io.File#getPath() 129 * @see java.lang.SecurityManager#checkRead(java.lang.String) 130 */ 131 public FileInputStream(File file) throws FileNotFoundException { 132 String name = (file != null ? file.getPath() : null); 133 SecurityManager security = System.getSecurityManager(); 134 if (security != null) { 135 security.checkRead(name); 136 } 137 if (name == null) { 138 throw new NullPointerException(); 139 } 140 if (file.isInvalid()) { 141 throw new FileNotFoundException("Invalid file path"); 142 } 143 fd = new FileDescriptor(); 144 fd.incrementAndGetUseCount(); 145 this.path = name; 146 open(name); 147 } 148 149 /** 150 * Creates a <code>FileInputStream</code> by using the file descriptor 151 * <code>fdObj</code>, which represents an existing connection to an 152 * actual file in the file system. 153 * <p> 154 * If there is a security manager, its <code>checkRead</code> method is 155 * called with the file descriptor <code>fdObj</code> as its argument to 156 * see if it's ok to read the file descriptor. If read access is denied 157 * to the file descriptor a <code>SecurityException</code> is thrown. 158 * <p> 159 * If <code>fdObj</code> is null then a <code>NullPointerException</code> 160 * is thrown. 161 * <p> 162 * This constructor does not throw an exception if <code>fdObj</code> 163 * is {@link java.io.FileDescriptor#valid() invalid}. 164 * However, if the methods are invoked on the resulting stream to attempt 165 * I/O on the stream, an <code>IOException</code> is thrown. 166 * 167 * @param fdObj the file descriptor to be opened for reading. 168 * @throws SecurityException if a security manager exists and its 169 * <code>checkRead</code> method denies read access to the 170 * file descriptor. 171 * @see SecurityManager#checkRead(java.io.FileDescriptor) 172 */ 173 public FileInputStream(FileDescriptor fdObj) { 174 SecurityManager security = System.getSecurityManager(); 175 if (fdObj == null) { 176 throw new NullPointerException(); 177 } 178 if (security != null) { 179 security.checkRead(fdObj); 180 } 181 fd = fdObj; 182 path = null; 183 184 /* 185 * FileDescriptor is being shared by streams. 186 * Ensure that it's GC'ed only when all the streams/channels are done 187 * using it. 188 */ 189 fd.incrementAndGetUseCount(); 190 } 191 192 /** 193 * Opens the specified file for reading. 194 * @param name the name of the file 195 */ 196 private native void open(String name) throws FileNotFoundException; 197 198 /** 199 * Reads a byte of data from this input stream. This method blocks 200 * if no input is yet available. 201 * 202 * @return the next byte of data, or <code>-1</code> if the end of the 203 * file is reached. 204 * @exception IOException if an I/O error occurs. 205 */ 206 public int read() throws IOException { 207 Object traceContext = IoTrace.fileReadBegin(path); 208 int b = 0; 209 try { 210 b = read0(); 211 } finally { 212 IoTrace.fileReadEnd(traceContext, b == -1 ? 0 : 1); 213 } 214 return b; 215 } 216 217 private native int read0() throws IOException; 218 219 /** 220 * Reads a subarray as a sequence of bytes. 221 * @param b the data to be written 222 * @param off the start offset in the data 223 * @param len the number of bytes that are written 224 * @exception IOException If an I/O error has occurred. 225 */ 226 private native int readBytes(byte b[], int off, int len) throws IOException; 227 228 /** 229 * Reads up to <code>b.length</code> bytes of data from this input 230 * stream into an array of bytes. This method blocks until some input 231 * is available. 232 * 233 * @param b the buffer into which the data is read. 234 * @return the total number of bytes read into the buffer, or 235 * <code>-1</code> if there is no more data because the end of 236 * the file has been reached. 237 * @exception IOException if an I/O error occurs. 238 */ 239 public int read(byte b[]) throws IOException { 240 Object traceContext = IoTrace.fileReadBegin(path); 241 int bytesRead = 0; 242 try { 243 bytesRead = readBytes(b, 0, b.length); 244 } finally { 245 IoTrace.fileReadEnd(traceContext, bytesRead == -1 ? 0 : bytesRead); 246 } 247 return bytesRead; 248 } 249 250 /** 251 * Reads up to <code>len</code> bytes of data from this input stream 252 * into an array of bytes. If <code>len</code> is not zero, the method 253 * blocks until some input is available; otherwise, no 254 * bytes are read and <code>0</code> is returned. 255 * 256 * @param b the buffer into which the data is read. 257 * @param off the start offset in the destination array <code>b</code> 258 * @param len the maximum number of bytes read. 259 * @return the total number of bytes read into the buffer, or 260 * <code>-1</code> if there is no more data because the end of 261 * the file has been reached. 262 * @exception NullPointerException If <code>b</code> is <code>null</code>. 263 * @exception IndexOutOfBoundsException If <code>off</code> is negative, 264 * <code>len</code> is negative, or <code>len</code> is greater than 265 * <code>b.length - off</code> 266 * @exception IOException if an I/O error occurs. 267 */ 268 public int read(byte b[], int off, int len) throws IOException { 269 Object traceContext = IoTrace.fileReadBegin(path); 270 int bytesRead = 0; 271 try { 272 bytesRead = readBytes(b, off, len); 273 } finally { 274 IoTrace.fileReadEnd(traceContext, bytesRead == -1 ? 0 : bytesRead); 275 } 276 return bytesRead; 277 } 278 279 /** 280 * Skips over and discards <code>n</code> bytes of data from the 281 * input stream. 282 * 283 * <p>The <code>skip</code> method may, for a variety of 284 * reasons, end up skipping over some smaller number of bytes, 285 * possibly <code>0</code>. If <code>n</code> is negative, an 286 * <code>IOException</code> is thrown, even though the <code>skip</code> 287 * method of the {@link InputStream} superclass does nothing in this case. 288 * The actual number of bytes skipped is returned. 289 * 290 * <p>This method may skip more bytes than are remaining in the backing 291 * file. This produces no exception and the number of bytes skipped 292 * may include some number of bytes that were beyond the EOF of the 293 * backing file. Attempting to read from the stream after skipping past 294 * the end will result in -1 indicating the end of the file. 295 * 296 * @param n the number of bytes to be skipped. 297 * @return the actual number of bytes skipped. 298 * @exception IOException if n is negative, if the stream does not 299 * support seek, or if an I/O error occurs. 300 */ 301 public native long skip(long n) throws IOException; 302 303 /** 304 * Returns an estimate of the number of remaining bytes that can be read (or 305 * skipped over) from this input stream without blocking by the next 306 * invocation of a method for this input stream. The next invocation might be 307 * the same thread or another thread. A single read or skip of this 308 * many bytes will not block, but may read or skip fewer bytes. 309 * 310 * <p> In some cases, a non-blocking read (or skip) may appear to be 311 * blocked when it is merely slow, for example when reading large 312 * files over slow networks. 313 * 314 * @return an estimate of the number of remaining bytes that can be read 315 * (or skipped over) from this input stream without blocking. 316 * @exception IOException if this file input stream has been closed by calling 317 * {@code close} or an I/O error occurs. 318 */ 319 public native int available() throws IOException; 320 321 /** 322 * Closes this file input stream and releases any system resources 323 * associated with the stream. 324 * 325 * <p> If this stream has an associated channel then the channel is closed 326 * as well. 327 * 328 * @exception IOException if an I/O error occurs. 329 * 330 * @revised 1.4 331 * @spec JSR-51 332 */ 333 public void close() throws IOException { 334 synchronized (closeLock) { 335 if (closed) { 336 return; 337 } 338 closed = true; 339 } 340 if (channel != null) { 341 /* 342 * Decrement the FD use count associated with the channel 343 * The use count is incremented whenever a new channel 344 * is obtained from this stream. 345 */ 346 fd.decrementAndGetUseCount(); 347 channel.close(); 348 } 349 350 /* 351 * Decrement the FD use count associated with this stream 352 */ 353 int useCount = fd.decrementAndGetUseCount(); 354 355 /* 356 * If FileDescriptor is still in use by another stream, the finalizer 357 * will not close it. 358 */ 359 if ((useCount <= 0) || !isRunningFinalize()) { 360 close0(); 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 * Increment fd's use count. Invoking the channel's close() 402 * method will result in decrementing the use count set for 403 * the channel. 404 */ 405 fd.incrementAndGetUseCount(); 406 } 407 return channel; 408 } 409 } 410 411 private static native void initIDs(); 412 413 private native void close0() throws IOException; 414 415 static { 416 initIDs(); 417 } 418 419 /** 420 * Ensures that the <code>close</code> method of this file input stream is 421 * called when there are no more references to it. 422 * 423 * @exception IOException if an I/O error occurs. 424 * @see java.io.FileInputStream#close() 425 */ 426 protected void finalize() throws IOException { 427 if ((fd != null) && (fd != FileDescriptor.in)) { 428 429 /* 430 * Finalizer should not release the FileDescriptor if another 431 * stream is still using it. If the user directly invokes 432 * close() then the FileDescriptor is also released. 433 */ 434 runningFinalize.set(Boolean.TRUE); 435 try { 436 close(); 437 } finally { 438 runningFinalize.set(Boolean.FALSE); 439 } 440 } 441 } 442} 443