diff -r 000000000000 -r 588d5bf7a560 rt/emul/compact/src/main/java/java/io/FileOutputStream.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/main/java/java/io/FileOutputStream.java Thu Oct 03 15:40:35 2013 +0200 @@ -0,0 +1,451 @@ +/* + * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.io; + +import java.nio.channels.FileChannel; +import sun.nio.ch.FileChannelImpl; + + +/** + * A file output stream is an output stream for writing data to a + * File or to a FileDescriptor. Whether or not + * a file is available or may be created depends upon the underlying + * platform. Some platforms, in particular, allow a file to be opened + * for writing by only one FileOutputStream (or other + * file-writing object) at a time. In such situations the constructors in + * this class will fail if the file involved is already open. + * + *

FileOutputStream is meant for writing streams of raw bytes + * such as image data. For writing streams of characters, consider using + * FileWriter. + * + * @author Arthur van Hoff + * @see java.io.File + * @see java.io.FileDescriptor + * @see java.io.FileInputStream + * @see java.nio.file.Files#newOutputStream + * @since JDK1.0 + */ +public +class FileOutputStream extends OutputStream +{ + /** + * The system dependent file descriptor. + */ + private final FileDescriptor fd; + + /** + * True if the file is opened for append. + */ + private final boolean append; + + /** + * The associated channel, initalized lazily. + */ + private FileChannel channel; + + private final Object closeLock = new Object(); + private volatile boolean closed = false; + private static final ThreadLocal runningFinalize = + new ThreadLocal<>(); + + private static boolean isRunningFinalize() { + Boolean val; + if ((val = runningFinalize.get()) != null) + return val.booleanValue(); + return false; + } + + /** + * Creates a file output stream to write to the file with the + * specified name. A new FileDescriptor object is + * created to represent this file connection. + *

+ * First, if there is a security manager, its checkWrite + * method is called with name as its argument. + *

+ * If the file exists but is a directory rather than a regular file, does + * not exist but cannot be created, or cannot be opened for any other + * reason then a FileNotFoundException is thrown. + * + * @param name the system-dependent filename + * @exception FileNotFoundException if the file exists but is a directory + * rather than a regular file, does not exist but cannot + * be created, or cannot be opened for any other reason + * @exception SecurityException if a security manager exists and its + * checkWrite method denies write access + * to the file. + * @see java.lang.SecurityManager#checkWrite(java.lang.String) + */ + public FileOutputStream(String name) throws FileNotFoundException { + this(name != null ? new File(name) : null, false); + } + + /** + * Creates a file output stream to write to the file with the specified + * name. If the second argument is true, then + * bytes will be written to the end of the file rather than the beginning. + * A new FileDescriptor object is created to represent this + * file connection. + *

+ * First, if there is a security manager, its checkWrite + * method is called with name as its argument. + *

+ * If the file exists but is a directory rather than a regular file, does + * not exist but cannot be created, or cannot be opened for any other + * reason then a FileNotFoundException is thrown. + * + * @param name the system-dependent file name + * @param append if true, then bytes will be written + * to the end of the file rather than the beginning + * @exception FileNotFoundException if the file exists but is a directory + * rather than a regular file, does not exist but cannot + * be created, or cannot be opened for any other reason. + * @exception SecurityException if a security manager exists and its + * checkWrite method denies write access + * to the file. + * @see java.lang.SecurityManager#checkWrite(java.lang.String) + * @since JDK1.1 + */ + public FileOutputStream(String name, boolean append) + throws FileNotFoundException + { + this(name != null ? new File(name) : null, append); + } + + /** + * Creates a file output stream to write to the file represented by + * the specified File object. A new + * FileDescriptor object is created to represent this + * file connection. + *

+ * First, if there is a security manager, its checkWrite + * method is called with the path represented by the file + * argument as its argument. + *

+ * If the file exists but is a directory rather than a regular file, does + * not exist but cannot be created, or cannot be opened for any other + * reason then a FileNotFoundException is thrown. + * + * @param file the file to be opened for writing. + * @exception FileNotFoundException if the file exists but is a directory + * rather than a regular file, does not exist but cannot + * be created, or cannot be opened for any other reason + * @exception SecurityException if a security manager exists and its + * checkWrite method denies write access + * to the file. + * @see java.io.File#getPath() + * @see java.lang.SecurityException + * @see java.lang.SecurityManager#checkWrite(java.lang.String) + */ + public FileOutputStream(File file) throws FileNotFoundException { + this(file, false); + } + + /** + * Creates a file output stream to write to the file represented by + * the specified File object. If the second argument is + * true, then bytes will be written to the end of the file + * rather than the beginning. A new FileDescriptor object is + * created to represent this file connection. + *

+ * First, if there is a security manager, its checkWrite + * method is called with the path represented by the file + * argument as its argument. + *

+ * If the file exists but is a directory rather than a regular file, does + * not exist but cannot be created, or cannot be opened for any other + * reason then a FileNotFoundException is thrown. + * + * @param file the file to be opened for writing. + * @param append if true, then bytes will be written + * to the end of the file rather than the beginning + * @exception FileNotFoundException if the file exists but is a directory + * rather than a regular file, does not exist but cannot + * be created, or cannot be opened for any other reason + * @exception SecurityException if a security manager exists and its + * checkWrite method denies write access + * to the file. + * @see java.io.File#getPath() + * @see java.lang.SecurityException + * @see java.lang.SecurityManager#checkWrite(java.lang.String) + * @since 1.4 + */ + public FileOutputStream(File file, boolean append) + throws FileNotFoundException + { + String name = (file != null ? file.getPath() : null); + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkWrite(name); + } + if (name == null) { + throw new NullPointerException(); + } + this.fd = new FileDescriptor(); + this.append = append; + + fd.incrementAndGetUseCount(); + open(name, append); + } + + /** + * Creates a file output stream to write to the specified file + * descriptor, which represents an existing connection to an actual + * file in the file system. + *

+ * First, if there is a security manager, its checkWrite + * method is called with the file descriptor fdObj + * argument as its argument. + *

+ * If fdObj is null then a NullPointerException + * is thrown. + *

+ * This constructor does not throw an exception if fdObj + * is {@link java.io.FileDescriptor#valid() invalid}. + * However, if the methods are invoked on the resulting stream to attempt + * I/O on the stream, an IOException is thrown. + * + * @param fdObj the file descriptor to be opened for writing + * @exception SecurityException if a security manager exists and its + * checkWrite method denies + * write access to the file descriptor + * @see java.lang.SecurityManager#checkWrite(java.io.FileDescriptor) + */ + public FileOutputStream(FileDescriptor fdObj) { + SecurityManager security = System.getSecurityManager(); + if (fdObj == null) { + throw new NullPointerException(); + } + if (security != null) { + security.checkWrite(fdObj); + } + this.fd = fdObj; + this.append = false; + + /* + * FileDescriptor is being shared by streams. + * Ensure that it's GC'ed only when all the streams/channels are done + * using it. + */ + fd.incrementAndGetUseCount(); + } + + /** + * Opens a file, with the specified name, for overwriting or appending. + * @param name name of file to be opened + * @param append whether the file is to be opened in append mode + */ + private native void open(String name, boolean append) + throws FileNotFoundException; + + /** + * Writes the specified byte to this file output stream. + * + * @param b the byte to be written. + * @param append {@code true} if the write operation first + * advances the position to the end of file + */ + private native void write(int b, boolean append) throws IOException; + + /** + * Writes the specified byte to this file output stream. Implements + * the write method of OutputStream. + * + * @param b the byte to be written. + * @exception IOException if an I/O error occurs. + */ + public void write(int b) throws IOException { + write(b, append); + } + + /** + * Writes a sub array as a sequence of bytes. + * @param b the data to be written + * @param off the start offset in the data + * @param len the number of bytes that are written + * @param append {@code true} to first advance the position to the + * end of file + * @exception IOException If an I/O error has occurred. + */ + private native void writeBytes(byte b[], int off, int len, boolean append) + throws IOException; + + /** + * Writes b.length bytes from the specified byte array + * to this file output stream. + * + * @param b the data. + * @exception IOException if an I/O error occurs. + */ + public void write(byte b[]) throws IOException { + writeBytes(b, 0, b.length, append); + } + + /** + * Writes len bytes from the specified byte array + * starting at offset off to this file output stream. + * + * @param b the data. + * @param off the start offset in the data. + * @param len the number of bytes to write. + * @exception IOException if an I/O error occurs. + */ + public void write(byte b[], int off, int len) throws IOException { + writeBytes(b, off, len, append); + } + + /** + * Closes this file output stream and releases any system resources + * associated with this stream. This file output stream may no longer + * be used for writing bytes. + * + *

If this stream has an associated channel then the channel is closed + * as well. + * + * @exception IOException if an I/O error occurs. + * + * @revised 1.4 + * @spec JSR-51 + */ + public void close() throws IOException { + synchronized (closeLock) { + if (closed) { + return; + } + closed = true; + } + + if (channel != null) { + /* + * Decrement FD use count associated with the channel + * The use count is incremented whenever a new channel + * is obtained from this stream. + */ + fd.decrementAndGetUseCount(); + channel.close(); + } + + /* + * Decrement FD use count associated with this stream + */ + int useCount = fd.decrementAndGetUseCount(); + + /* + * If FileDescriptor is still in use by another stream, the finalizer + * will not close it. + */ + if ((useCount <= 0) || !isRunningFinalize()) { + close0(); + } + } + + /** + * Returns the file descriptor associated with this stream. + * + * @return the FileDescriptor object that represents + * the connection to the file in the file system being used + * by this FileOutputStream object. + * + * @exception IOException if an I/O error occurs. + * @see java.io.FileDescriptor + */ + public final FileDescriptor getFD() throws IOException { + if (fd != null) return fd; + throw new IOException(); + } + + /** + * Returns the unique {@link java.nio.channels.FileChannel FileChannel} + * object associated with this file output stream.

+ * + *

The initial {@link java.nio.channels.FileChannel#position() + * position} of the returned channel will be equal to the + * number of bytes written to the file so far unless this stream is in + * append mode, in which case it will be equal to the size of the file. + * Writing bytes to this stream will increment the channel's position + * accordingly. Changing the channel's position, either explicitly or by + * writing, will change this stream's file position. + * + * @return the file channel associated with this file output stream + * + * @since 1.4 + * @spec JSR-51 + */ + public FileChannel getChannel() { + synchronized (this) { + if (channel == null) { + channel = FileChannelImpl.open(fd, false, true, append, this); + + /* + * Increment fd's use count. Invoking the channel's close() + * method will result in decrementing the use count set for + * the channel. + */ + fd.incrementAndGetUseCount(); + } + return channel; + } + } + + /** + * Cleans up the connection to the file, and ensures that the + * close method of this file output stream is + * called when there are no more references to this stream. + * + * @exception IOException if an I/O error occurs. + * @see java.io.FileInputStream#close() + */ + protected void finalize() throws IOException { + if (fd != null) { + if (fd == FileDescriptor.out || fd == FileDescriptor.err) { + flush(); + } else { + + /* + * Finalizer should not release the FileDescriptor if another + * stream is still using it. If the user directly invokes + * close() then the FileDescriptor is also released. + */ + runningFinalize.set(Boolean.TRUE); + try { + close(); + } finally { + runningFinalize.set(Boolean.FALSE); + } + } + } + } + + private native void close0() throws IOException; + + private static native void initIDs(); + + static { + initIDs(); + } + +}