1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. Oracle designates this 9 * particular file as subject to the "Classpath" exception as provided 10 * by Oracle in the LICENSE file that accompanied this code. 11 * 12 * This code is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 * version 2 for more details (a copy is included in the LICENSE file that 16 * accompanied this code). 17 * 18 * You should have received a copy of the GNU General Public License version 19 * 2 along with this work; if not, write to the Free Software Foundation, 20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 * 22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 * or visit www.oracle.com if you need additional information or have any 24 * questions. 25 */ 26 27 package java.io; 28 29 import java.nio.channels.FileChannel; 30 31 import dalvik.system.BlockGuard; 32 import dalvik.system.CloseGuard; 33 import sun.nio.ch.FileChannelImpl; 34 import sun.misc.IoTrace; 35 import libcore.io.IoBridge; 36 37 /** 38 * A file output stream is an output stream for writing data to a 39 * <code>File</code> or to a <code>FileDescriptor</code>. Whether or not 40 * a file is available or may be created depends upon the underlying 41 * platform. Some platforms, in particular, allow a file to be opened 42 * for writing by only one <tt>FileOutputStream</tt> (or other 43 * file-writing object) at a time. In such situations the constructors in 44 * this class will fail if the file involved is already open. 45 * 46 * <p><code>FileOutputStream</code> is meant for writing streams of raw bytes 47 * such as image data. For writing streams of characters, consider using 48 * <code>FileWriter</code>. 49 * 50 * @author Arthur van Hoff 51 * @see java.io.File 52 * @see java.io.FileDescriptor 53 * @see java.io.FileInputStream 54 * @see java.nio.file.Files#newOutputStream 55 * @since JDK1.0 56 */ 57 public 58 class FileOutputStream extends OutputStream 59 { 60 /** 61 * The system dependent file descriptor. 62 */ 63 private final FileDescriptor fd; 64 65 /** 66 * The path of the referenced file (null if the stream is created with a file descriptor) 67 */ 68 private final String path; 69 70 /** 71 * True if the file is opened for append. 72 */ 73 private final boolean append; 74 75 /** 76 * The associated channel, initalized lazily. 77 */ 78 private FileChannel channel; 79 80 private final Object closeLock = new Object(); 81 private volatile boolean closed = false; 82 83 private final CloseGuard guard = CloseGuard.get(); 84 private final boolean isFdOwner; 85 86 /** 87 * Creates a file output stream to write to the file with the 88 * specified name. A new <code>FileDescriptor</code> object is 89 * created to represent this file connection. 90 * <p> 91 * First, if there is a security manager, its <code>checkWrite</code> 92 * method is called with <code>name</code> as its argument. 93 * <p> 94 * If the file exists but is a directory rather than a regular file, does 95 * not exist but cannot be created, or cannot be opened for any other 96 * reason then a <code>FileNotFoundException</code> is thrown. 97 * 98 * @param name the system-dependent filename 99 * @exception FileNotFoundException if the file exists but is a directory 100 * rather than a regular file, does not exist but cannot 101 * be created, or cannot be opened for any other reason 102 * @exception SecurityException if a security manager exists and its 103 * <code>checkWrite</code> method denies write access 104 * to the file. 105 * @see java.lang.SecurityManager#checkWrite(java.lang.String) 106 */ FileOutputStream(String name)107 public FileOutputStream(String name) throws FileNotFoundException { 108 this(name != null ? new File(name) : null, false); 109 } 110 111 /** 112 * Creates a file output stream to write to the file with the specified 113 * name. If the second argument is <code>true</code>, then 114 * bytes will be written to the end of the file rather than the beginning. 115 * A new <code>FileDescriptor</code> object is created to represent this 116 * file connection. 117 * <p> 118 * First, if there is a security manager, its <code>checkWrite</code> 119 * method is called with <code>name</code> as its argument. 120 * <p> 121 * If the file exists but is a directory rather than a regular file, does 122 * not exist but cannot be created, or cannot be opened for any other 123 * reason then a <code>FileNotFoundException</code> is thrown. 124 * 125 * @param name the system-dependent file name 126 * @param append if <code>true</code>, then bytes will be written 127 * to the end of the file rather than the beginning 128 * @exception FileNotFoundException if the file exists but is a directory 129 * rather than a regular file, does not exist but cannot 130 * be created, or cannot be opened for any other reason. 131 * @exception SecurityException if a security manager exists and its 132 * <code>checkWrite</code> method denies write access 133 * to the file. 134 * @see java.lang.SecurityManager#checkWrite(java.lang.String) 135 * @since JDK1.1 136 */ FileOutputStream(String name, boolean append)137 public FileOutputStream(String name, boolean append) 138 throws FileNotFoundException 139 { 140 this(name != null ? new File(name) : null, append); 141 } 142 143 /** 144 * Creates a file output stream to write to the file represented by 145 * the specified <code>File</code> object. A new 146 * <code>FileDescriptor</code> object is created to represent this 147 * file connection. 148 * <p> 149 * First, if there is a security manager, its <code>checkWrite</code> 150 * method is called with the path represented by the <code>file</code> 151 * argument as its argument. 152 * <p> 153 * If the file exists but is a directory rather than a regular file, does 154 * not exist but cannot be created, or cannot be opened for any other 155 * reason then a <code>FileNotFoundException</code> is thrown. 156 * 157 * @param file the file to be opened for writing. 158 * @exception FileNotFoundException if the file exists but is a directory 159 * rather than a regular file, does not exist but cannot 160 * be created, or cannot be opened for any other reason 161 * @exception SecurityException if a security manager exists and its 162 * <code>checkWrite</code> method denies write access 163 * to the file. 164 * @see java.io.File#getPath() 165 * @see java.lang.SecurityException 166 * @see java.lang.SecurityManager#checkWrite(java.lang.String) 167 */ FileOutputStream(File file)168 public FileOutputStream(File file) throws FileNotFoundException { 169 this(file, false); 170 } 171 172 /** 173 * Creates a file output stream to write to the file represented by 174 * the specified <code>File</code> object. If the second argument is 175 * <code>true</code>, then bytes will be written to the end of the file 176 * rather than the beginning. A new <code>FileDescriptor</code> object is 177 * created to represent this file connection. 178 * <p> 179 * First, if there is a security manager, its <code>checkWrite</code> 180 * method is called with the path represented by the <code>file</code> 181 * argument as its argument. 182 * <p> 183 * If the file exists but is a directory rather than a regular file, does 184 * not exist but cannot be created, or cannot be opened for any other 185 * reason then a <code>FileNotFoundException</code> is thrown. 186 * 187 * @param file the file to be opened for writing. 188 * @param append if <code>true</code>, then bytes will be written 189 * to the end of the file rather than the beginning 190 * @exception FileNotFoundException if the file exists but is a directory 191 * rather than a regular file, does not exist but cannot 192 * be created, or cannot be opened for any other reason 193 * @exception SecurityException if a security manager exists and its 194 * <code>checkWrite</code> method denies write access 195 * to the file. 196 * @see java.io.File#getPath() 197 * @see java.lang.SecurityException 198 * @see java.lang.SecurityManager#checkWrite(java.lang.String) 199 * @since 1.4 200 */ FileOutputStream(File file, boolean append)201 public FileOutputStream(File file, boolean append) 202 throws FileNotFoundException 203 { 204 String name = (file != null ? file.getPath() : null); 205 SecurityManager security = System.getSecurityManager(); 206 if (security != null) { 207 security.checkWrite(name); 208 } 209 if (name == null) { 210 throw new NullPointerException(); 211 } 212 if (file.isInvalid()) { 213 throw new FileNotFoundException("Invalid file path"); 214 } 215 this.fd = new FileDescriptor(); 216 this.append = append; 217 this.path = name; 218 this.isFdOwner = true; 219 220 BlockGuard.getThreadPolicy().onWriteToDisk(); 221 open(name, append); 222 guard.open("close"); 223 } 224 225 /** 226 * Creates a file output stream to write to the specified file 227 * descriptor, which represents an existing connection to an actual 228 * file in the file system. 229 * <p> 230 * First, if there is a security manager, its <code>checkWrite</code> 231 * method is called with the file descriptor <code>fdObj</code> 232 * argument as its argument. 233 * <p> 234 * If <code>fdObj</code> is null then a <code>NullPointerException</code> 235 * is thrown. 236 * <p> 237 * This constructor does not throw an exception if <code>fdObj</code> 238 * is {@link java.io.FileDescriptor#valid() invalid}. 239 * However, if the methods are invoked on the resulting stream to attempt 240 * I/O on the stream, an <code>IOException</code> is thrown. 241 * 242 * @param fdObj the file descriptor to be opened for writing 243 * @exception SecurityException if a security manager exists and its 244 * <code>checkWrite</code> method denies 245 * write access to the file descriptor 246 * @see java.lang.SecurityManager#checkWrite(java.io.FileDescriptor) 247 */ FileOutputStream(FileDescriptor fdObj)248 public FileOutputStream(FileDescriptor fdObj) { 249 this(fdObj, false /* isOwner */); 250 } 251 252 /** 253 * Internal constructor for {@code FileOutputStream} objects where the file descriptor 254 * is owned by this tream. 255 * 256 * @hide 257 */ FileOutputStream(FileDescriptor fdObj, boolean isFdOwner)258 public FileOutputStream(FileDescriptor fdObj, boolean isFdOwner) { 259 if (fdObj == null) { 260 throw new NullPointerException("fdObj == null"); 261 } 262 263 this.fd = fdObj; 264 this.path = null; 265 this.append = false; 266 this.isFdOwner = isFdOwner; 267 } 268 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 */ open(String name, boolean append)274 private native void open(String name, boolean append) 275 throws FileNotFoundException; 276 277 /** 278 * Writes the specified byte to this file output stream. Implements 279 * the <code>write</code> method of <code>OutputStream</code>. 280 * 281 * @param b the byte to be written. 282 * @exception IOException if an I/O error occurs. 283 */ write(int b)284 public void write(int b) throws IOException { 285 write(new byte[] { (byte) b }, 0, 1); 286 } 287 288 /** 289 * Writes <code>b.length</code> bytes from the specified byte array 290 * to this file output stream. 291 * 292 * @param b the data. 293 * @exception IOException if an I/O error occurs. 294 */ write(byte b[])295 public void write(byte b[]) throws IOException { 296 write(b, 0, b.length); 297 } 298 299 /** 300 * Writes <code>len</code> bytes from the specified byte array 301 * starting at offset <code>off</code> to this file output stream. 302 * 303 * @param b the data. 304 * @param off the start offset in the data. 305 * @param len the number of bytes to write. 306 * @exception IOException if an I/O error occurs. 307 */ write(byte b[], int off, int len)308 public void write(byte b[], int off, int len) throws IOException { 309 if (closed && len > 0) { 310 throw new IOException("Stream Closed"); 311 } 312 313 Object traceContext = IoTrace.fileWriteBegin(path); 314 int bytesWritten = 0; 315 try { 316 IoBridge.write(fd, b, off, len); 317 bytesWritten = len; 318 } finally { 319 IoTrace.fileWriteEnd(traceContext, bytesWritten); 320 } 321 } 322 323 /** 324 * Closes this file output stream and releases any system resources 325 * associated with this stream. This file output stream may no longer 326 * be used for writing bytes. 327 * 328 * <p> If this stream has an associated channel then the channel is closed 329 * as well. 330 * 331 * @exception IOException if an I/O error occurs. 332 * 333 * @revised 1.4 334 * @spec JSR-51 335 */ close()336 public void close() throws IOException { 337 synchronized (closeLock) { 338 if (closed) { 339 return; 340 } 341 closed = true; 342 } 343 344 guard.close(); 345 346 if (channel != null) { 347 /* 348 * Decrement FD use count associated with the channel 349 * The use count is incremented whenever a new channel 350 * is obtained from this stream. 351 */ 352 channel.close(); 353 } 354 355 356 if (isFdOwner) { 357 IoBridge.closeAndSignalBlockedThreads(fd); 358 } 359 } 360 361 /** 362 * Returns the file descriptor associated with this stream. 363 * 364 * @return the <code>FileDescriptor</code> object that represents 365 * the connection to the file in the file system being used 366 * by this <code>FileOutputStream</code> object. 367 * 368 * @exception IOException if an I/O error occurs. 369 * @see java.io.FileDescriptor 370 */ getFD()371 public final FileDescriptor getFD() throws IOException { 372 if (fd != null) return fd; 373 throw new IOException(); 374 } 375 376 /** 377 * Returns the unique {@link java.nio.channels.FileChannel FileChannel} 378 * object associated with this file output stream. </p> 379 * 380 * <p> The initial {@link java.nio.channels.FileChannel#position() 381 * </code>position<code>} of the returned channel will be equal to the 382 * number of bytes written to the file so far unless this stream is in 383 * append mode, in which case it will be equal to the size of the file. 384 * Writing bytes to this stream will increment the channel's position 385 * accordingly. Changing the channel's position, either explicitly or by 386 * writing, will change this stream's file position. 387 * 388 * @return the file channel associated with this file output stream 389 * 390 * @since 1.4 391 * @spec JSR-51 392 */ getChannel()393 public FileChannel getChannel() { 394 synchronized (this) { 395 if (channel == null) { 396 channel = FileChannelImpl.open(fd, path, false, true, append, this); 397 } 398 return channel; 399 } 400 } 401 402 /** 403 * Cleans up the connection to the file, and ensures that the 404 * <code>close</code> method of this file output stream is 405 * called when there are no more references to this stream. 406 * 407 * @exception IOException if an I/O error occurs. 408 * @see java.io.FileInputStream#close() 409 */ finalize()410 protected void finalize() throws IOException { 411 if (guard != null) { 412 guard.warnIfOpen(); 413 } 414 415 if (fd != null) { 416 if (fd == FileDescriptor.out || fd == FileDescriptor.err) { 417 flush(); 418 } else { 419 close(); 420 } 421 } 422 } 423 } 424