1 /* 2 * Copyright (c) 1994, 2023, 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 26 package java.io; 27 28 import java.nio.channels.FileChannel; 29 import java.util.Arrays; 30 import jdk.internal.misc.Blocker; 31 import jdk.internal.util.ArraysSupport; 32 import sun.nio.ch.FileChannelImpl; 33 34 /** 35 * A {@code FileInputStream} obtains input bytes 36 * from a file in a file system. What files 37 * are available depends on the host environment. 38 * 39 * <p>{@code FileInputStream} is meant for reading streams of raw bytes 40 * such as image data. For reading streams of characters, consider using 41 * {@code FileReader}. 42 * 43 * @apiNote 44 * The {@link #close} method should be called to release resources used by this 45 * stream, either directly, or with the {@code try}-with-resources statement. 46 * 47 * @implSpec 48 * Subclasses are responsible for the cleanup of resources acquired by the subclass. 49 * Subclasses requiring that resource cleanup take place after a stream becomes 50 * unreachable should use {@link java.lang.ref.Cleaner} or some other mechanism. 51 * 52 * @author Arthur van Hoff 53 * @see java.io.File 54 * @see java.io.FileDescriptor 55 * @see java.io.FileOutputStream 56 * @see java.nio.file.Files#newInputStream 57 * @since 1.0 58 */ 59 public class FileInputStream extends InputStream 60 { 61 private static final int DEFAULT_BUFFER_SIZE = 8192; 62 63 /* File Descriptor - handle to the open file */ 64 private final FileDescriptor fd; 65 66 /** 67 * The path of the referenced file 68 * (null if the stream is created with a file descriptor) 69 */ 70 private final String path; 71 72 private volatile FileChannel channel; 73 74 private final Object closeLock = new Object(); 75 76 private volatile boolean closed; 77 78 /** 79 * Creates a {@code FileInputStream} by 80 * opening a connection to an actual file, 81 * the file named by the path name {@code name} 82 * in the file system. A new {@code FileDescriptor} 83 * object is created to represent this file 84 * connection. 85 * <p> 86 * First, if there is a security 87 * manager, its {@code checkRead} method 88 * is called with the {@code name} argument 89 * as its argument. 90 * <p> 91 * If the named file does not exist, is a directory rather than a regular 92 * file, or for some other reason cannot be opened for reading then a 93 * {@code FileNotFoundException} is thrown. 94 * 95 * @param name the system-dependent file name. 96 * @throws FileNotFoundException if the file does not exist, 97 * is a directory rather than a regular file, 98 * or for some other reason cannot be opened for 99 * reading. 100 * @throws SecurityException if a security manager exists and its 101 * {@code checkRead} method denies read access 102 * to the file. 103 * @see java.lang.SecurityManager#checkRead(java.lang.String) 104 */ 105 public FileInputStream(String name) throws FileNotFoundException { 106 this(name != null ? new File(name) : null); 107 } 108 109 /** 110 * Creates a {@code FileInputStream} by 111 * opening a connection to an actual file, 112 * the file named by the {@code File} 113 * object {@code file} in the file system. 114 * A new {@code FileDescriptor} object 115 * is created to represent this file connection. 116 * <p> 117 * First, if there is a security manager, 118 * its {@code checkRead} method is called 119 * with the path represented by the {@code file} 120 * argument as its argument. 121 * <p> 122 * If the named file does not exist, is a directory rather than a regular 123 * file, or for some other reason cannot be opened for reading then a 124 * {@code FileNotFoundException} is thrown. 125 * 126 * @param file the file to be opened for reading. 127 * @throws FileNotFoundException if the file does not exist, 128 * is a directory rather than a regular file, 129 * or for some other reason cannot be opened for 130 * reading. 131 * @throws SecurityException if a security manager exists and its 132 * {@code checkRead} method denies read access to the file. 133 * @see java.io.File#getPath() 134 * @see java.lang.SecurityManager#checkRead(java.lang.String) 135 */ 136 @SuppressWarnings("this-escape") 137 public FileInputStream(File file) throws FileNotFoundException { 138 String name = (file != null ? file.getPath() : null); 139 @SuppressWarnings("removal") 140 SecurityManager security = System.getSecurityManager(); 141 if (security != null) { 142 security.checkRead(name); 143 } 144 if (name == null) { 145 throw new NullPointerException(); 146 } 147 if (file.isInvalid()) { 148 throw new FileNotFoundException("Invalid file path"); 149 } 150 fd = new FileDescriptor(); 151 fd.attach(this); 152 path = name; 153 open(name); 154 FileCleanable.register(fd); // open set the fd, register the cleanup 155 } 156 157 /** 158 * Creates a {@code FileInputStream} by using the file descriptor 159 * {@code fdObj}, which represents an existing connection to an 160 * actual file in the file system. 161 * <p> 162 * If there is a security manager, its {@code checkRead} method is 163 * called with the file descriptor {@code fdObj} as its argument to 164 * see if it's ok to read the file descriptor. If read access is denied 165 * to the file descriptor a {@code SecurityException} is thrown. 166 * <p> 167 * If {@code fdObj} is null then a {@code NullPointerException} 168 * is thrown. 169 * <p> 170 * This constructor does not throw an exception if {@code fdObj} 171 * is {@link java.io.FileDescriptor#valid() invalid}. 172 * However, if the methods are invoked on the resulting stream to attempt 173 * I/O on the stream, an {@code IOException} is thrown. 174 * 175 * @param fdObj the file descriptor to be opened for reading. 176 * @throws SecurityException if a security manager exists and its 177 * {@code checkRead} method denies read access to the 178 * file descriptor. 179 * @see SecurityManager#checkRead(java.io.FileDescriptor) 180 */ 181 @SuppressWarnings("this-escape") 182 public FileInputStream(FileDescriptor fdObj) { 183 @SuppressWarnings("removal") 184 SecurityManager security = System.getSecurityManager(); 185 if (fdObj == null) { 186 throw new NullPointerException(); 187 } 188 if (security != null) { 189 security.checkRead(fdObj); 190 } 191 fd = fdObj; 192 path = null; 193 194 /* 195 * FileDescriptor is being shared by streams. 196 * Register this stream with FileDescriptor tracker. 197 */ 198 fd.attach(this); 199 } 200 201 /** 202 * Opens the specified file for reading. 203 * @param name the name of the file 204 */ 205 private native void open0(String name) throws FileNotFoundException; 206 207 // wrap native call to allow instrumentation 208 /** 209 * Opens the specified file for reading. 210 * @param name the name of the file 211 */ 212 private void open(String name) throws FileNotFoundException { 213 long comp = Blocker.begin(); 214 try { 215 open0(name); 216 } finally { 217 Blocker.end(comp); 218 } 219 } 220 221 /** 222 * Reads a byte of data from this input stream. This method blocks 223 * if no input is yet available. 224 * 225 * @return the next byte of data, or {@code -1} if the end of the 226 * file is reached. 227 * @throws IOException {@inheritDoc} 228 */ 229 @Override 230 public int read() throws IOException { 231 long comp = Blocker.begin(); 232 try { 233 return read0(); 234 } finally { 235 Blocker.end(comp); 236 } 237 } 238 239 private native int read0() throws IOException; 240 241 /** 242 * Reads a subarray as a sequence of bytes. 243 * @param b the data to be written 244 * @param off the start offset in the data 245 * @param len the number of bytes that are written 246 * @throws IOException If an I/O error has occurred. 247 */ 248 private native int readBytes(byte[] b, int off, int len) throws IOException; 249 250 /** 251 * Reads up to {@code b.length} bytes of data from this input 252 * stream into an array of bytes. This method blocks until some input 253 * is available. 254 * 255 * @param b {@inheritDoc} 256 * @return the total number of bytes read into the buffer, or 257 * {@code -1} if there is no more data because the end of 258 * the file has been reached. 259 * @throws IOException if an I/O error occurs. 260 */ 261 @Override 262 public int read(byte[] b) throws IOException { 263 long comp = Blocker.begin(); 264 try { 265 return readBytes(b, 0, b.length); 266 } finally { 267 Blocker.end(comp); 268 } 269 } 270 271 /** 272 * Reads up to {@code len} bytes of data from this input stream 273 * into an array of bytes. If {@code len} is not zero, the method 274 * blocks until some input is available; otherwise, no 275 * bytes are read and {@code 0} is returned. 276 * 277 * @param b {@inheritDoc} 278 * @param off {@inheritDoc} 279 * @param len {@inheritDoc} 280 * @return {@inheritDoc} 281 * @throws NullPointerException {@inheritDoc} 282 * @throws IndexOutOfBoundsException {@inheritDoc} 283 * @throws IOException if an I/O error occurs. 284 */ 285 @Override 286 public int read(byte[] b, int off, int len) throws IOException { 287 long comp = Blocker.begin(); 288 try { 289 return readBytes(b, off, len); 290 } finally { 291 Blocker.end(comp); 292 } 293 } 294 295 @Override 296 public byte[] readAllBytes() throws IOException { 297 long length = length(); 298 long position = position(); 299 long size = length - position; 300 301 if (length <= 0 || size <= 0) 302 return super.readAllBytes(); 303 304 if (size > (long) Integer.MAX_VALUE) { 305 String msg = 306 String.format("Required array size too large for %s: %d = %d - %d", 307 path, size, length, position); 308 throw new OutOfMemoryError(msg); 309 } 310 311 int capacity = (int)size; 312 byte[] buf = new byte[capacity]; 313 314 int nread = 0; 315 int n; 316 for (;;) { 317 // read to EOF which may read more or less than initial size, e.g., 318 // file is truncated while we are reading 319 while ((n = read(buf, nread, capacity - nread)) > 0) 320 nread += n; 321 322 // if last call to read() returned -1, we are done; otherwise, 323 // try to read one more byte and if that fails we're done too 324 if (n < 0 || (n = read()) < 0) 325 break; 326 327 // one more byte was read; need to allocate a larger buffer 328 capacity = Math.max(ArraysSupport.newLength(capacity, 329 1, // min growth 330 capacity), // pref growth 331 DEFAULT_BUFFER_SIZE); 332 buf = Arrays.copyOf(buf, capacity); 333 buf[nread++] = (byte)n; 334 } 335 return (capacity == nread) ? buf : Arrays.copyOf(buf, nread); 336 } 337 338 @Override 339 public byte[] readNBytes(int len) throws IOException { 340 if (len < 0) 341 throw new IllegalArgumentException("len < 0"); 342 if (len == 0) 343 return new byte[0]; 344 345 long length = length(); 346 long position = position(); 347 long size = length - position; 348 349 if (length <= 0 || size <= 0) 350 return super.readNBytes(len); 351 352 int capacity = (int)Math.min(len, size); 353 byte[] buf = new byte[capacity]; 354 355 int remaining = capacity; 356 int nread = 0; 357 int n; 358 do { 359 n = read(buf, nread, remaining); 360 if (n > 0) { 361 nread += n; 362 remaining -= n; 363 } else if (n == 0) { 364 // Block until a byte is read or EOF is detected 365 byte b = (byte)read(); 366 if (b == -1 ) 367 break; 368 buf[nread++] = b; 369 remaining--; 370 } 371 } while (n >= 0 && remaining > 0); 372 return (capacity == nread) ? buf : Arrays.copyOf(buf, nread); 373 } 374 375 /** 376 * {@inheritDoc} 377 */ 378 @Override 379 public long transferTo(OutputStream out) throws IOException { 380 long transferred = 0L; 381 if (out instanceof FileOutputStream fos) { 382 FileChannel fc = getChannel(); 383 long pos = fc.position(); 384 transferred = fc.transferTo(pos, Long.MAX_VALUE, fos.getChannel()); 385 long newPos = pos + transferred; 386 fc.position(newPos); 387 if (newPos >= fc.size()) { 388 return transferred; 389 } 390 } 391 try { 392 return Math.addExact(transferred, super.transferTo(out)); 393 } catch (ArithmeticException ignore) { 394 return Long.MAX_VALUE; 395 } 396 } 397 398 private long length() throws IOException { 399 long comp = Blocker.begin(); 400 try { 401 return length0(); 402 } finally { 403 Blocker.end(comp); 404 } 405 } 406 private native long length0() throws IOException; 407 408 private long position() throws IOException { 409 long comp = Blocker.begin(); 410 try { 411 return position0(); 412 } finally { 413 Blocker.end(comp); 414 } 415 } 416 private native long position0() throws IOException; 417 418 /** 419 * Skips over and discards {@code n} bytes of data from the 420 * input stream. 421 * 422 * <p>The {@code skip} method may, for a variety of 423 * reasons, end up skipping over some smaller number of bytes, 424 * possibly {@code 0}. If {@code n} is negative, the method 425 * will try to skip backwards. In case the backing file does not support 426 * backward skip at its current position, an {@code IOException} is 427 * thrown. The actual number of bytes skipped is returned. If it skips 428 * forwards, it returns a positive value. If it skips backwards, it 429 * returns a negative value. 430 * 431 * <p>This method may skip more bytes than what are remaining in the 432 * backing file. This produces no exception and the number of bytes skipped 433 * may include some number of bytes that were beyond the EOF of the 434 * backing file. Attempting to read from the stream after skipping past 435 * the end will result in -1 indicating the end of the file. 436 * 437 * @param n {@inheritDoc} 438 * @return the actual number of bytes skipped. 439 * @throws IOException if n is negative, if the stream does not 440 * support seek, or if an I/O error occurs. 441 */ 442 @Override 443 public long skip(long n) throws IOException { 444 long comp = Blocker.begin(); 445 try { 446 return skip0(n); 447 } finally { 448 Blocker.end(comp); 449 } 450 } 451 452 private native long skip0(long n) throws IOException; 453 454 /** 455 * Returns an estimate of the number of remaining bytes that can be read (or 456 * skipped over) from this input stream without blocking by the next 457 * invocation of a method for this input stream. Returns 0 when the file 458 * position is beyond EOF. The next invocation might be the same thread 459 * or another thread. A single read or skip of this many bytes will not 460 * block, but may read or skip fewer bytes. 461 * 462 * <p> In some cases, a non-blocking read (or skip) may appear to be 463 * blocked when it is merely slow, for example when reading large 464 * files over slow networks. 465 * 466 * @return an estimate of the number of remaining bytes that can be read 467 * (or skipped over) from this input stream without blocking. 468 * @throws IOException if this file input stream has been closed by calling 469 * {@code close} or an I/O error occurs. 470 */ 471 @Override 472 public int available() throws IOException { 473 long comp = Blocker.begin(); 474 try { 475 return available0(); 476 } finally { 477 Blocker.end(comp); 478 } 479 } 480 481 private native int available0() throws IOException; 482 483 /** 484 * Closes this file input stream and releases any system resources 485 * associated with the stream. 486 * 487 * <p> If this stream has an associated channel then the channel is closed 488 * as well. 489 * 490 * @apiNote 491 * Overriding {@link #close} to perform cleanup actions is reliable 492 * only when called directly or when called by try-with-resources. 493 * 494 * @implSpec 495 * Subclasses requiring that resource cleanup take place after a stream becomes 496 * unreachable should use the {@link java.lang.ref.Cleaner} mechanism. 497 * 498 * <p> 499 * If this stream has an associated channel then this method will close the 500 * channel, which in turn will close this stream. Subclasses that override 501 * this method should be prepared to handle possible reentrant invocation. 502 * 503 * @throws IOException {@inheritDoc} 504 */ 505 @Override 506 public void close() throws IOException { 507 if (closed) { 508 return; 509 } 510 synchronized (closeLock) { 511 if (closed) { 512 return; 513 } 514 closed = true; 515 } 516 517 FileChannel fc = channel; 518 if (fc != null) { 519 // possible race with getChannel(), benign since 520 // FileChannel.close is final and idempotent 521 fc.close(); 522 } 523 524 fd.closeAll(new Closeable() { 525 public void close() throws IOException { 526 fd.close(); 527 } 528 }); 529 } 530 531 /** 532 * Returns the {@code FileDescriptor} 533 * object that represents the connection to 534 * the actual file in the file system being 535 * used by this {@code FileInputStream}. 536 * 537 * @return the file descriptor object associated with this stream. 538 * @throws IOException if an I/O error occurs. 539 * @see java.io.FileDescriptor 540 */ 541 public final FileDescriptor getFD() throws IOException { 542 if (fd != null) { 543 return fd; 544 } 545 throw new IOException(); 546 } 547 548 /** 549 * Returns the unique {@link java.nio.channels.FileChannel FileChannel} 550 * object associated with this file input stream. 551 * 552 * <p> The initial {@link java.nio.channels.FileChannel#position() 553 * position} of the returned channel will be equal to the 554 * number of bytes read from the file so far. Reading bytes from this 555 * stream will increment the channel's position. Changing the channel's 556 * position, either explicitly or by reading, will change this stream's 557 * file position. 558 * 559 * @return the file channel associated with this file input stream 560 * 561 * @since 1.4 562 */ 563 public FileChannel getChannel() { 564 FileChannel fc = this.channel; 565 if (fc == null) { 566 synchronized (this) { 567 fc = this.channel; 568 if (fc == null) { 569 this.channel = fc = FileChannelImpl.open(fd, path, true, 570 false, false, this); 571 if (closed) { 572 try { 573 // possible race with close(), benign since 574 // FileChannel.close is final and idempotent 575 fc.close(); 576 } catch (IOException ioe) { 577 throw new InternalError(ioe); // should not happen 578 } 579 } 580 } 581 } 582 } 583 return fc; 584 } 585 586 private static native void initIDs(); 587 588 static { 589 initIDs(); 590 } 591 }