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