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