1/* 2 * Copyright (c) 1994, 2017, 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 jdk.internal.misc.SharedSecrets; 30import jdk.internal.misc.JavaIOFileDescriptorAccess; 31import sun.nio.ch.FileChannelImpl; 32 33 34/** 35 * A file output stream is an output stream for writing data to a 36 * <code>File</code> or to a <code>FileDescriptor</code>. Whether or not 37 * a file is available or may be created depends upon the underlying 38 * platform. Some platforms, in particular, allow a file to be opened 39 * for writing by only one {@code FileOutputStream} (or other 40 * file-writing object) at a time. In such situations the constructors in 41 * this class will fail if the file involved is already open. 42 * 43 * <p><code>FileOutputStream</code> is meant for writing streams of raw bytes 44 * such as image data. For writing streams of characters, consider using 45 * <code>FileWriter</code>. 46 * 47 * @author Arthur van Hoff 48 * @see java.io.File 49 * @see java.io.FileDescriptor 50 * @see java.io.FileInputStream 51 * @see java.nio.file.Files#newOutputStream 52 * @since 1.0 53 */ 54public 55class FileOutputStream extends OutputStream 56{ 57 /** 58 * Access to FileDescriptor internals. 59 */ 60 private static final JavaIOFileDescriptorAccess fdAccess = 61 SharedSecrets.getJavaIOFileDescriptorAccess(); 62 63 /** 64 * The system dependent file descriptor. 65 */ 66 private final FileDescriptor fd; 67 68 /** 69 * The associated channel, initialized lazily. 70 */ 71 private volatile FileChannel channel; 72 73 /** 74 * The path of the referenced file 75 * (null if the stream is created with a file descriptor) 76 */ 77 private final String path; 78 79 private final Object closeLock = new Object(); 80 81 private volatile boolean closed; 82 83 /** 84 * Creates a file output stream to write to the file with the 85 * specified name. A new <code>FileDescriptor</code> object is 86 * created to represent this file connection. 87 * <p> 88 * First, if there is a security manager, its <code>checkWrite</code> 89 * method is called with <code>name</code> as its argument. 90 * <p> 91 * If the file exists but is a directory rather than a regular file, does 92 * not exist but cannot be created, or cannot be opened for any other 93 * reason then a <code>FileNotFoundException</code> is thrown. 94 * <p> 95 * @implSpec Invoking this constructor with the parameter {@code name} is 96 * equivalent to invoking {@link #FileOutputStream(String,boolean) 97 * new FileOutputStream(name, false)}. 98 * 99 * @param name the system-dependent filename 100 * @exception FileNotFoundException if the file exists but is a directory 101 * rather than a regular file, does not exist but cannot 102 * be created, or cannot be opened for any other reason 103 * @exception SecurityException if a security manager exists and its 104 * <code>checkWrite</code> method denies write access 105 * to the file. 106 * @see java.lang.SecurityManager#checkWrite(java.lang.String) 107 */ 108 public FileOutputStream(String name) throws FileNotFoundException { 109 this(name != null ? new File(name) : null, false); 110 } 111 112 /** 113 * Creates a file output stream to write to the file with the specified 114 * name. If the second argument is <code>true</code>, then 115 * bytes will be written to the end of the file rather than the beginning. 116 * A new <code>FileDescriptor</code> object is created to represent this 117 * file connection. 118 * <p> 119 * First, if there is a security manager, its <code>checkWrite</code> 120 * method is called with <code>name</code> as its argument. 121 * <p> 122 * If the file exists but is a directory rather than a regular file, does 123 * not exist but cannot be created, or cannot be opened for any other 124 * reason then a <code>FileNotFoundException</code> is thrown. 125 * 126 * @param name the system-dependent file name 127 * @param append if <code>true</code>, then bytes will be written 128 * to the end of the file rather than the beginning 129 * @exception FileNotFoundException if the file exists but is a directory 130 * rather than a regular file, does not exist but cannot 131 * be created, or cannot be opened for any other reason. 132 * @exception SecurityException if a security manager exists and its 133 * <code>checkWrite</code> method denies write access 134 * to the file. 135 * @see java.lang.SecurityManager#checkWrite(java.lang.String) 136 * @since 1.1 137 */ 138 public FileOutputStream(String name, boolean append) 139 throws FileNotFoundException 140 { 141 this(name != null ? new File(name) : null, append); 142 } 143 144 /** 145 * Creates a file output stream to write to the file represented by 146 * the specified <code>File</code> object. A new 147 * <code>FileDescriptor</code> object is created to represent this 148 * file connection. 149 * <p> 150 * First, if there is a security manager, its <code>checkWrite</code> 151 * method is called with the path represented by the <code>file</code> 152 * argument as its argument. 153 * <p> 154 * If the file exists but is a directory rather than a regular file, does 155 * not exist but cannot be created, or cannot be opened for any other 156 * reason then a <code>FileNotFoundException</code> is thrown. 157 * 158 * @param file the file to be opened for writing. 159 * @exception FileNotFoundException if the file exists but is a directory 160 * rather than a regular file, does not exist but cannot 161 * be created, or cannot be opened for any other reason 162 * @exception SecurityException if a security manager exists and its 163 * <code>checkWrite</code> method denies write access 164 * to the file. 165 * @see java.io.File#getPath() 166 * @see java.lang.SecurityException 167 * @see java.lang.SecurityManager#checkWrite(java.lang.String) 168 */ 169 public FileOutputStream(File file) throws FileNotFoundException { 170 this(file, false); 171 } 172 173 /** 174 * Creates a file output stream to write to the file represented by 175 * the specified <code>File</code> object. If the second argument is 176 * <code>true</code>, then bytes will be written to the end of the file 177 * rather than the beginning. A new <code>FileDescriptor</code> object is 178 * created to represent this file connection. 179 * <p> 180 * First, if there is a security manager, its <code>checkWrite</code> 181 * method is called with the path represented by the <code>file</code> 182 * argument as its argument. 183 * <p> 184 * If the file exists but is a directory rather than a regular file, does 185 * not exist but cannot be created, or cannot be opened for any other 186 * reason then a <code>FileNotFoundException</code> is thrown. 187 * 188 * @param file the file to be opened for writing. 189 * @param append if <code>true</code>, then bytes will be written 190 * to the end of the file rather than the beginning 191 * @exception FileNotFoundException if the file exists but is a directory 192 * rather than a regular file, does not exist but cannot 193 * be created, or cannot be opened for any other reason 194 * @exception SecurityException if a security manager exists and its 195 * <code>checkWrite</code> method denies write access 196 * to the file. 197 * @see java.io.File#getPath() 198 * @see java.lang.SecurityException 199 * @see java.lang.SecurityManager#checkWrite(java.lang.String) 200 * @since 1.4 201 */ 202 public FileOutputStream(File file, boolean append) 203 throws FileNotFoundException 204 { 205 String name = (file != null ? file.getPath() : null); 206 SecurityManager security = System.getSecurityManager(); 207 if (security != null) { 208 security.checkWrite(name); 209 } 210 if (name == null) { 211 throw new NullPointerException(); 212 } 213 if (file.isInvalid()) { 214 throw new FileNotFoundException("Invalid file path"); 215 } 216 this.fd = new FileDescriptor(); 217 fd.attach(this); 218 this.path = name; 219 220 open(name, append); 221 } 222 223 /** 224 * Creates a file output stream to write to the specified file 225 * descriptor, which represents an existing connection to an actual 226 * file in the file system. 227 * <p> 228 * First, if there is a security manager, its <code>checkWrite</code> 229 * method is called with the file descriptor <code>fdObj</code> 230 * argument as its argument. 231 * <p> 232 * If <code>fdObj</code> is null then a <code>NullPointerException</code> 233 * is thrown. 234 * <p> 235 * This constructor does not throw an exception if <code>fdObj</code> 236 * is {@link java.io.FileDescriptor#valid() invalid}. 237 * However, if the methods are invoked on the resulting stream to attempt 238 * I/O on the stream, an <code>IOException</code> is thrown. 239 * 240 * @param fdObj the file descriptor to be opened for writing 241 * @exception SecurityException if a security manager exists and its 242 * <code>checkWrite</code> method denies 243 * write access to the file descriptor 244 * @see java.lang.SecurityManager#checkWrite(java.io.FileDescriptor) 245 */ 246 public FileOutputStream(FileDescriptor fdObj) { 247 SecurityManager security = System.getSecurityManager(); 248 if (fdObj == null) { 249 throw new NullPointerException(); 250 } 251 if (security != null) { 252 security.checkWrite(fdObj); 253 } 254 this.fd = fdObj; 255 this.path = null; 256 257 fd.attach(this); 258 } 259 260 /** 261 * Opens a file, with the specified name, for overwriting or appending. 262 * @param name name of file to be opened 263 * @param append whether the file is to be opened in append mode 264 */ 265 private native void open0(String name, boolean append) 266 throws FileNotFoundException; 267 268 // wrap native call to allow instrumentation 269 /** 270 * Opens a file, with the specified name, for overwriting or appending. 271 * @param name name of file to be opened 272 * @param append whether the file is to be opened in append mode 273 */ 274 private void open(String name, boolean append) 275 throws FileNotFoundException { 276 open0(name, append); 277 } 278 279 /** 280 * Writes the specified byte to this file output stream. 281 * 282 * @param b the byte to be written. 283 * @param append {@code true} if the write operation first 284 * advances the position to the end of file 285 */ 286 private native void write(int b, boolean append) throws IOException; 287 288 /** 289 * Writes the specified byte to this file output stream. Implements 290 * the <code>write</code> method of <code>OutputStream</code>. 291 * 292 * @param b the byte to be written. 293 * @exception IOException if an I/O error occurs. 294 */ 295 public void write(int b) throws IOException { 296 write(b, fdAccess.getAppend(fd)); 297 } 298 299 /** 300 * Writes a sub array as a sequence of bytes. 301 * @param b the data to be written 302 * @param off the start offset in the data 303 * @param len the number of bytes that are written 304 * @param append {@code true} to first advance the position to the 305 * end of file 306 * @exception IOException If an I/O error has occurred. 307 */ 308 private native void writeBytes(byte b[], int off, int len, boolean append) 309 throws IOException; 310 311 /** 312 * Writes <code>b.length</code> bytes from the specified byte array 313 * to this file output stream. 314 * 315 * @param b the data. 316 * @exception IOException if an I/O error occurs. 317 */ 318 public void write(byte b[]) throws IOException { 319 writeBytes(b, 0, b.length, fdAccess.getAppend(fd)); 320 } 321 322 /** 323 * Writes <code>len</code> bytes from the specified byte array 324 * starting at offset <code>off</code> to this file output stream. 325 * 326 * @param b the data. 327 * @param off the start offset in the data. 328 * @param len the number of bytes to write. 329 * @exception IOException if an I/O error occurs. 330 */ 331 public void write(byte b[], int off, int len) throws IOException { 332 writeBytes(b, off, len, fdAccess.getAppend(fd)); 333 } 334 335 /** 336 * Closes this file output stream and releases any system resources 337 * associated with this stream. This file output stream may no longer 338 * be used for writing bytes. 339 * 340 * <p> If this stream has an associated channel then the channel is closed 341 * as well. 342 * 343 * @exception IOException if an I/O error occurs. 344 * 345 * @revised 1.4 346 * @spec JSR-51 347 */ 348 public void close() throws IOException { 349 if (closed) { 350 return; 351 } 352 synchronized (closeLock) { 353 if (closed) { 354 return; 355 } 356 closed = true; 357 } 358 359 FileChannel fc = channel; 360 if (fc != null) { 361 // possible race with getChannel(), benign since 362 // FileChannel.close is final and idempotent 363 fc.close(); 364 } 365 366 fd.closeAll(new Closeable() { 367 public void close() throws IOException { 368 close0(); 369 } 370 }); 371 } 372 373 /** 374 * Returns the file descriptor associated with this stream. 375 * 376 * @return the <code>FileDescriptor</code> object that represents 377 * the connection to the file in the file system being used 378 * by this <code>FileOutputStream</code> object. 379 * 380 * @exception IOException if an I/O error occurs. 381 * @see java.io.FileDescriptor 382 */ 383 public final FileDescriptor getFD() throws IOException { 384 if (fd != null) { 385 return fd; 386 } 387 throw new IOException(); 388 } 389 390 /** 391 * Returns the unique {@link java.nio.channels.FileChannel FileChannel} 392 * object associated with this file output stream. 393 * 394 * <p> The initial {@link java.nio.channels.FileChannel#position() 395 * position} of the returned channel will be equal to the 396 * number of bytes written to the file so far unless this stream is in 397 * append mode, in which case it will be equal to the size of the file. 398 * Writing bytes to this stream will increment the channel's position 399 * accordingly. Changing the channel's position, either explicitly or by 400 * writing, will change this stream's file position. 401 * 402 * @return the file channel associated with this file output stream 403 * 404 * @since 1.4 405 * @spec JSR-51 406 */ 407 public FileChannel getChannel() { 408 FileChannel fc = this.channel; 409 if (fc == null) { 410 synchronized (this) { 411 fc = this.channel; 412 if (fc == null) { 413 this.channel = fc = FileChannelImpl.open(fd, path, false, true, this); 414 if (closed) { 415 try { 416 // possible race with close(), benign since 417 // FileChannel.close is final and idempotent 418 fc.close(); 419 } catch (IOException ioe) { 420 throw new InternalError(ioe); // should not happen 421 } 422 } 423 } 424 } 425 } 426 return fc; 427 } 428 429 /** 430 * Cleans up the connection to the file, and ensures that the 431 * <code>close</code> method of this file output stream is 432 * called when there are no more references to this stream. 433 * 434 * @deprecated The {@code finalize} method has been deprecated. 435 * Subclasses that override {@code finalize} in order to perform cleanup 436 * should be modified to use alternative cleanup mechanisms and 437 * to remove the overriding {@code finalize} method. 438 * When overriding the {@code finalize} method, its implementation must explicitly 439 * ensure that {@code super.finalize()} is invoked as described in {@link Object#finalize}. 440 * See the specification for {@link Object#finalize()} for further 441 * information about migration options. 442 * @exception IOException if an I/O error occurs. 443 * @see java.io.FileInputStream#close() 444 */ 445 @Deprecated(since="9") 446 protected void finalize() throws IOException { 447 if (fd != null) { 448 if (fd == FileDescriptor.out || fd == FileDescriptor.err) { 449 flush(); 450 } else { 451 /* if fd is shared, the references in FileDescriptor 452 * will ensure that finalizer is only called when 453 * safe to do so. All references using the fd have 454 * become unreachable. We can call close() 455 */ 456 close(); 457 } 458 } 459 } 460 461 private native void close0() throws IOException; 462 463 private static native void initIDs(); 464 465 static { 466 initIDs(); 467 } 468 469} 470