Path: blob/master/src/java.base/share/classes/java/io/FileOutputStream.java
41152 views
/*1* Copyright (c) 1994, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package java.io;2627import java.nio.channels.FileChannel;28import jdk.internal.access.SharedSecrets;29import jdk.internal.access.JavaIOFileDescriptorAccess;30import sun.nio.ch.FileChannelImpl;313233/**34* A file output stream is an output stream for writing data to a35* {@code File} or to a {@code FileDescriptor}. Whether or not36* a file is available or may be created depends upon the underlying37* platform. Some platforms, in particular, allow a file to be opened38* for writing by only one {@code FileOutputStream} (or other39* file-writing object) at a time. In such situations the constructors in40* this class will fail if the file involved is already open.41*42* <p>{@code FileOutputStream} is meant for writing streams of raw bytes43* such as image data. For writing streams of characters, consider using44* {@code FileWriter}.45*46* @apiNote47* To release resources used by this stream {@link #close} should be called48* directly or by try-with-resources. Subclasses are responsible for the cleanup49* of resources acquired by the subclass.50* Subclasses that override {@link #finalize} in order to perform cleanup51* should be modified to use alternative cleanup mechanisms such as52* {@link java.lang.ref.Cleaner} and remove the overriding {@code finalize} method.53*54* @implSpec55* If this FileOutputStream has been subclassed and the {@link #close}56* method has been overridden, the {@link #close} method will be57* called when the FileInputStream is unreachable.58* Otherwise, it is implementation specific how the resource cleanup described in59* {@link #close} is performed.60*61* @author Arthur van Hoff62* @see java.io.File63* @see java.io.FileDescriptor64* @see java.io.FileInputStream65* @see java.nio.file.Files#newOutputStream66* @since 1.067*/68public class FileOutputStream extends OutputStream69{70/**71* Access to FileDescriptor internals.72*/73private static final JavaIOFileDescriptorAccess fdAccess =74SharedSecrets.getJavaIOFileDescriptorAccess();7576/**77* The system dependent file descriptor.78*/79private final FileDescriptor fd;8081/**82* The associated channel, initialized lazily.83*/84private volatile FileChannel channel;8586/**87* The path of the referenced file88* (null if the stream is created with a file descriptor)89*/90private final String path;9192private final Object closeLock = new Object();9394private volatile boolean closed;9596/**97* Creates a file output stream to write to the file with the98* specified name. A new {@code FileDescriptor} object is99* created to represent this file connection.100* <p>101* First, if there is a security manager, its {@code checkWrite}102* method is called with {@code name} as its argument.103* <p>104* If the file exists but is a directory rather than a regular file, does105* not exist but cannot be created, or cannot be opened for any other106* reason then a {@code FileNotFoundException} is thrown.107*108* @implSpec Invoking this constructor with the parameter {@code name} is109* equivalent to invoking {@link #FileOutputStream(String,boolean)110* new FileOutputStream(name, false)}.111*112* @param name the system-dependent filename113* @throws FileNotFoundException if the file exists but is a directory114* rather than a regular file, does not exist but cannot115* be created, or cannot be opened for any other reason116* @throws SecurityException if a security manager exists and its117* {@code checkWrite} method denies write access118* to the file.119* @see java.lang.SecurityManager#checkWrite(java.lang.String)120*/121public FileOutputStream(String name) throws FileNotFoundException {122this(name != null ? new File(name) : null, false);123}124125/**126* Creates a file output stream to write to the file with the specified127* name. If the second argument is {@code true}, then128* bytes will be written to the end of the file rather than the beginning.129* A new {@code FileDescriptor} object is created to represent this130* file connection.131* <p>132* First, if there is a security manager, its {@code checkWrite}133* method is called with {@code name} as its argument.134* <p>135* If the file exists but is a directory rather than a regular file, does136* not exist but cannot be created, or cannot be opened for any other137* reason then a {@code FileNotFoundException} is thrown.138*139* @param name the system-dependent file name140* @param append if {@code true}, then bytes will be written141* to the end of the file rather than the beginning142* @throws FileNotFoundException if the file exists but is a directory143* rather than a regular file, does not exist but cannot144* be created, or cannot be opened for any other reason.145* @throws SecurityException if a security manager exists and its146* {@code checkWrite} method denies write access147* to the file.148* @see java.lang.SecurityManager#checkWrite(java.lang.String)149* @since 1.1150*/151public FileOutputStream(String name, boolean append)152throws FileNotFoundException153{154this(name != null ? new File(name) : null, append);155}156157/**158* Creates a file output stream to write to the file represented by159* the specified {@code File} object. A new160* {@code FileDescriptor} object is created to represent this161* file connection.162* <p>163* First, if there is a security manager, its {@code checkWrite}164* method is called with the path represented by the {@code file}165* argument as its argument.166* <p>167* If the file exists but is a directory rather than a regular file, does168* not exist but cannot be created, or cannot be opened for any other169* reason then a {@code FileNotFoundException} is thrown.170*171* @param file the file to be opened for writing.172* @throws FileNotFoundException if the file exists but is a directory173* rather than a regular file, does not exist but cannot174* be created, or cannot be opened for any other reason175* @throws SecurityException if a security manager exists and its176* {@code checkWrite} method denies write access177* to the file.178* @see java.io.File#getPath()179* @see java.lang.SecurityException180* @see java.lang.SecurityManager#checkWrite(java.lang.String)181*/182public FileOutputStream(File file) throws FileNotFoundException {183this(file, false);184}185186/**187* Creates a file output stream to write to the file represented by188* the specified {@code File} object. If the second argument is189* {@code true}, then bytes will be written to the end of the file190* rather than the beginning. A new {@code FileDescriptor} object is191* created to represent this file connection.192* <p>193* First, if there is a security manager, its {@code checkWrite}194* method is called with the path represented by the {@code file}195* argument as its argument.196* <p>197* If the file exists but is a directory rather than a regular file, does198* not exist but cannot be created, or cannot be opened for any other199* reason then a {@code FileNotFoundException} is thrown.200*201* @param file the file to be opened for writing.202* @param append if {@code true}, then bytes will be written203* to the end of the file rather than the beginning204* @throws FileNotFoundException if the file exists but is a directory205* rather than a regular file, does not exist but cannot206* be created, or cannot be opened for any other reason207* @throws SecurityException if a security manager exists and its208* {@code checkWrite} method denies write access209* to the file.210* @see java.io.File#getPath()211* @see java.lang.SecurityException212* @see java.lang.SecurityManager#checkWrite(java.lang.String)213* @since 1.4214*/215public FileOutputStream(File file, boolean append)216throws FileNotFoundException217{218String name = (file != null ? file.getPath() : null);219@SuppressWarnings("removal")220SecurityManager security = System.getSecurityManager();221if (security != null) {222security.checkWrite(name);223}224if (name == null) {225throw new NullPointerException();226}227if (file.isInvalid()) {228throw new FileNotFoundException("Invalid file path");229}230this.fd = new FileDescriptor();231fd.attach(this);232this.path = name;233234open(name, append);235FileCleanable.register(fd); // open sets the fd, register the cleanup236}237238/**239* Creates a file output stream to write to the specified file240* descriptor, which represents an existing connection to an actual241* file in the file system.242* <p>243* First, if there is a security manager, its {@code checkWrite}244* method is called with the file descriptor {@code fdObj}245* argument as its argument.246* <p>247* If {@code fdObj} is null then a {@code NullPointerException}248* is thrown.249* <p>250* This constructor does not throw an exception if {@code fdObj}251* is {@link java.io.FileDescriptor#valid() invalid}.252* However, if the methods are invoked on the resulting stream to attempt253* I/O on the stream, an {@code IOException} is thrown.254*255* @param fdObj the file descriptor to be opened for writing256* @throws SecurityException if a security manager exists and its257* {@code checkWrite} method denies258* write access to the file descriptor259* @see java.lang.SecurityManager#checkWrite(java.io.FileDescriptor)260*/261public FileOutputStream(FileDescriptor fdObj) {262@SuppressWarnings("removal")263SecurityManager security = System.getSecurityManager();264if (fdObj == null) {265throw new NullPointerException();266}267if (security != null) {268security.checkWrite(fdObj);269}270this.fd = fdObj;271this.path = null;272273fd.attach(this);274}275276/**277* Opens a file, with the specified name, for overwriting or appending.278* @param name name of file to be opened279* @param append whether the file is to be opened in append mode280*/281private native void open0(String name, boolean append)282throws FileNotFoundException;283284// wrap native call to allow instrumentation285/**286* Opens a file, with the specified name, for overwriting or appending.287* @param name name of file to be opened288* @param append whether the file is to be opened in append mode289*/290private void open(String name, boolean append)291throws FileNotFoundException {292open0(name, append);293}294295/**296* Writes the specified byte to this file output stream.297*298* @param b the byte to be written.299* @param append {@code true} if the write operation first300* advances the position to the end of file301*/302private native void write(int b, boolean append) throws IOException;303304/**305* Writes the specified byte to this file output stream. Implements306* the {@code write} method of {@code OutputStream}.307*308* @param b the byte to be written.309* @throws IOException if an I/O error occurs.310*/311public void write(int b) throws IOException {312write(b, fdAccess.getAppend(fd));313}314315/**316* Writes a sub array as a sequence of bytes.317* @param b the data to be written318* @param off the start offset in the data319* @param len the number of bytes that are written320* @param append {@code true} to first advance the position to the321* end of file322* @throws IOException If an I/O error has occurred.323*/324private native void writeBytes(byte b[], int off, int len, boolean append)325throws IOException;326327/**328* Writes {@code b.length} bytes from the specified byte array329* to this file output stream.330*331* @param b the data.332* @throws IOException if an I/O error occurs.333*/334public void write(byte b[]) throws IOException {335writeBytes(b, 0, b.length, fdAccess.getAppend(fd));336}337338/**339* Writes {@code len} bytes from the specified byte array340* starting at offset {@code off} to this file output stream.341*342* @param b the data.343* @param off the start offset in the data.344* @param len the number of bytes to write.345* @throws IOException if an I/O error occurs.346*/347public void write(byte b[], int off, int len) throws IOException {348writeBytes(b, off, len, fdAccess.getAppend(fd));349}350351/**352* Closes this file output stream and releases any system resources353* associated with this stream. This file output stream may no longer354* be used for writing bytes.355*356* <p> If this stream has an associated channel then the channel is closed357* as well.358*359* @apiNote360* Overriding {@link #close} to perform cleanup actions is reliable361* only when called directly or when called by try-with-resources.362* Do not depend on finalization to invoke {@code close};363* finalization is not reliable and is deprecated.364* If cleanup of native resources is needed, other mechanisms such as365* {@linkplain java.lang.ref.Cleaner} should be used.366*367* @throws IOException if an I/O error occurs.368*369* @revised 1.4370*/371public void close() throws IOException {372if (closed) {373return;374}375synchronized (closeLock) {376if (closed) {377return;378}379closed = true;380}381382FileChannel fc = channel;383if (fc != null) {384// possible race with getChannel(), benign since385// FileChannel.close is final and idempotent386fc.close();387}388389fd.closeAll(new Closeable() {390public void close() throws IOException {391fd.close();392}393});394}395396/**397* Returns the file descriptor associated with this stream.398*399* @return the {@code FileDescriptor} object that represents400* the connection to the file in the file system being used401* by this {@code FileOutputStream} object.402*403* @throws IOException if an I/O error occurs.404* @see java.io.FileDescriptor405*/406public final FileDescriptor getFD() throws IOException {407if (fd != null) {408return fd;409}410throw new IOException();411}412413/**414* Returns the unique {@link java.nio.channels.FileChannel FileChannel}415* object associated with this file output stream.416*417* <p> The initial {@link java.nio.channels.FileChannel#position()418* position} of the returned channel will be equal to the419* number of bytes written to the file so far unless this stream is in420* append mode, in which case it will be equal to the size of the file.421* Writing bytes to this stream will increment the channel's position422* accordingly. Changing the channel's position, either explicitly or by423* writing, will change this stream's file position.424*425* @return the file channel associated with this file output stream426*427* @since 1.4428*/429public FileChannel getChannel() {430FileChannel fc = this.channel;431if (fc == null) {432synchronized (this) {433fc = this.channel;434if (fc == null) {435this.channel = fc = FileChannelImpl.open(fd, path, false,436true, false, this);437if (closed) {438try {439// possible race with close(), benign since440// FileChannel.close is final and idempotent441fc.close();442} catch (IOException ioe) {443throw new InternalError(ioe); // should not happen444}445}446}447}448}449return fc;450}451452private static native void initIDs();453454static {455initIDs();456}457}458459460