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.
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.
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).
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.
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
28 import java.nio.channels.FileChannel;
29 import sun.nio.ch.FileChannelImpl;
33 * A file output stream is an output stream for writing data to a
34 * <code>File</code> or to a <code>FileDescriptor</code>. Whether or not
35 * a file is available or may be created depends upon the underlying
36 * platform. Some platforms, in particular, allow a file to be opened
37 * for writing by only one <tt>FileOutputStream</tt> (or other
38 * file-writing object) at a time. In such situations the constructors in
39 * this class will fail if the file involved is already open.
41 * <p><code>FileOutputStream</code> is meant for writing streams of raw bytes
42 * such as image data. For writing streams of characters, consider using
43 * <code>FileWriter</code>.
45 * @author Arthur van Hoff
47 * @see java.io.FileDescriptor
48 * @see java.io.FileInputStream
49 * @see java.nio.file.Files#newOutputStream
53 class FileOutputStream extends OutputStream
56 * The system dependent file descriptor.
58 private final FileDescriptor fd;
61 * True if the file is opened for append.
63 private final boolean append;
66 * The associated channel, initalized lazily.
68 private FileChannel channel;
70 private final Object closeLock = new Object();
71 private volatile boolean closed = false;
72 private static final ThreadLocal<Boolean> runningFinalize =
75 private static boolean isRunningFinalize() {
77 if ((val = runningFinalize.get()) != null)
78 return val.booleanValue();
83 * Creates a file output stream to write to the file with the
84 * specified name. A new <code>FileDescriptor</code> object is
85 * created to represent this file connection.
87 * First, if there is a security manager, its <code>checkWrite</code>
88 * method is called with <code>name</code> as its argument.
90 * If the file exists but is a directory rather than a regular file, does
91 * not exist but cannot be created, or cannot be opened for any other
92 * reason then a <code>FileNotFoundException</code> is thrown.
94 * @param name the system-dependent filename
95 * @exception FileNotFoundException if the file exists but is a directory
96 * rather than a regular file, does not exist but cannot
97 * be created, or cannot be opened for any other reason
98 * @exception SecurityException if a security manager exists and its
99 * <code>checkWrite</code> method denies write access
101 * @see java.lang.SecurityManager#checkWrite(java.lang.String)
103 public FileOutputStream(String name) throws FileNotFoundException {
104 this(name != null ? new File(name) : null, false);
108 * Creates a file output stream to write to the file with the specified
109 * name. If the second argument is <code>true</code>, then
110 * bytes will be written to the end of the file rather than the beginning.
111 * A new <code>FileDescriptor</code> object is created to represent this
114 * First, if there is a security manager, its <code>checkWrite</code>
115 * method is called with <code>name</code> as its argument.
117 * If the file exists but is a directory rather than a regular file, does
118 * not exist but cannot be created, or cannot be opened for any other
119 * reason then a <code>FileNotFoundException</code> is thrown.
121 * @param name the system-dependent file name
122 * @param append if <code>true</code>, then bytes will be written
123 * to the end of the file rather than the beginning
124 * @exception FileNotFoundException if the file exists but is a directory
125 * rather than a regular file, does not exist but cannot
126 * be created, or cannot be opened for any other reason.
127 * @exception SecurityException if a security manager exists and its
128 * <code>checkWrite</code> method denies write access
130 * @see java.lang.SecurityManager#checkWrite(java.lang.String)
133 public FileOutputStream(String name, boolean append)
134 throws FileNotFoundException
136 this(name != null ? new File(name) : null, append);
140 * Creates a file output stream to write to the file represented by
141 * the specified <code>File</code> object. A new
142 * <code>FileDescriptor</code> object is created to represent this
145 * First, if there is a security manager, its <code>checkWrite</code>
146 * method is called with the path represented by the <code>file</code>
147 * argument as its argument.
149 * If the file exists but is a directory rather than a regular file, does
150 * not exist but cannot be created, or cannot be opened for any other
151 * reason then a <code>FileNotFoundException</code> is thrown.
153 * @param file the file to be opened for writing.
154 * @exception FileNotFoundException if the file exists but is a directory
155 * rather than a regular file, does not exist but cannot
156 * be created, or cannot be opened for any other reason
157 * @exception SecurityException if a security manager exists and its
158 * <code>checkWrite</code> method denies write access
160 * @see java.io.File#getPath()
161 * @see java.lang.SecurityException
162 * @see java.lang.SecurityManager#checkWrite(java.lang.String)
164 public FileOutputStream(File file) throws FileNotFoundException {
169 * Creates a file output stream to write to the file represented by
170 * the specified <code>File</code> object. If the second argument is
171 * <code>true</code>, then bytes will be written to the end of the file
172 * rather than the beginning. A new <code>FileDescriptor</code> object is
173 * created to represent this file connection.
175 * First, if there is a security manager, its <code>checkWrite</code>
176 * method is called with the path represented by the <code>file</code>
177 * argument as its argument.
179 * If the file exists but is a directory rather than a regular file, does
180 * not exist but cannot be created, or cannot be opened for any other
181 * reason then a <code>FileNotFoundException</code> is thrown.
183 * @param file the file to be opened for writing.
184 * @param append if <code>true</code>, then bytes will be written
185 * to the end of the file rather than the beginning
186 * @exception FileNotFoundException if the file exists but is a directory
187 * rather than a regular file, does not exist but cannot
188 * be created, or cannot be opened for any other reason
189 * @exception SecurityException if a security manager exists and its
190 * <code>checkWrite</code> method denies write access
192 * @see java.io.File#getPath()
193 * @see java.lang.SecurityException
194 * @see java.lang.SecurityManager#checkWrite(java.lang.String)
197 public FileOutputStream(File file, boolean append)
198 throws FileNotFoundException
200 String name = (file != null ? file.getPath() : null);
201 SecurityManager security = System.getSecurityManager();
202 if (security != null) {
203 security.checkWrite(name);
206 throw new NullPointerException();
208 this.fd = new FileDescriptor();
209 this.append = append;
211 fd.incrementAndGetUseCount();
216 * Creates a file output stream to write to the specified file
217 * descriptor, which represents an existing connection to an actual
218 * file in the file system.
220 * First, if there is a security manager, its <code>checkWrite</code>
221 * method is called with the file descriptor <code>fdObj</code>
222 * argument as its argument.
224 * If <code>fdObj</code> is null then a <code>NullPointerException</code>
227 * This constructor does not throw an exception if <code>fdObj</code>
228 * is {@link java.io.FileDescriptor#valid() invalid}.
229 * However, if the methods are invoked on the resulting stream to attempt
230 * I/O on the stream, an <code>IOException</code> is thrown.
232 * @param fdObj the file descriptor to be opened for writing
233 * @exception SecurityException if a security manager exists and its
234 * <code>checkWrite</code> method denies
235 * write access to the file descriptor
236 * @see java.lang.SecurityManager#checkWrite(java.io.FileDescriptor)
238 public FileOutputStream(FileDescriptor fdObj) {
239 SecurityManager security = System.getSecurityManager();
241 throw new NullPointerException();
243 if (security != null) {
244 security.checkWrite(fdObj);
250 * FileDescriptor is being shared by streams.
251 * Ensure that it's GC'ed only when all the streams/channels are done
254 fd.incrementAndGetUseCount();
258 * Opens a file, with the specified name, for overwriting or appending.
259 * @param name name of file to be opened
260 * @param append whether the file is to be opened in append mode
262 private native void open(String name, boolean append)
263 throws FileNotFoundException;
266 * Writes the specified byte to this file output stream.
268 * @param b the byte to be written.
269 * @param append {@code true} if the write operation first
270 * advances the position to the end of file
272 private native void write(int b, boolean append) throws IOException;
275 * Writes the specified byte to this file output stream. Implements
276 * the <code>write</code> method of <code>OutputStream</code>.
278 * @param b the byte to be written.
279 * @exception IOException if an I/O error occurs.
281 public void write(int b) throws IOException {
286 * Writes a sub array as a sequence of bytes.
287 * @param b the data to be written
288 * @param off the start offset in the data
289 * @param len the number of bytes that are written
290 * @param append {@code true} to first advance the position to the
292 * @exception IOException If an I/O error has occurred.
294 private native void writeBytes(byte b[], int off, int len, boolean append)
298 * Writes <code>b.length</code> bytes from the specified byte array
299 * to this file output stream.
302 * @exception IOException if an I/O error occurs.
304 public void write(byte b[]) throws IOException {
305 writeBytes(b, 0, b.length, append);
309 * Writes <code>len</code> bytes from the specified byte array
310 * starting at offset <code>off</code> to this file output stream.
313 * @param off the start offset in the data.
314 * @param len the number of bytes to write.
315 * @exception IOException if an I/O error occurs.
317 public void write(byte b[], int off, int len) throws IOException {
318 writeBytes(b, off, len, append);
322 * Closes this file output stream and releases any system resources
323 * associated with this stream. This file output stream may no longer
324 * be used for writing bytes.
326 * <p> If this stream has an associated channel then the channel is closed
329 * @exception IOException if an I/O error occurs.
334 public void close() throws IOException {
335 synchronized (closeLock) {
342 if (channel != null) {
344 * Decrement FD use count associated with the channel
345 * The use count is incremented whenever a new channel
346 * is obtained from this stream.
348 fd.decrementAndGetUseCount();
353 * Decrement FD use count associated with this stream
355 int useCount = fd.decrementAndGetUseCount();
358 * If FileDescriptor is still in use by another stream, the finalizer
361 if ((useCount <= 0) || !isRunningFinalize()) {
367 * Returns the file descriptor associated with this stream.
369 * @return the <code>FileDescriptor</code> object that represents
370 * the connection to the file in the file system being used
371 * by this <code>FileOutputStream</code> object.
373 * @exception IOException if an I/O error occurs.
374 * @see java.io.FileDescriptor
376 public final FileDescriptor getFD() throws IOException {
377 if (fd != null) return fd;
378 throw new IOException();
382 * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
383 * object associated with this file output stream. </p>
385 * <p> The initial {@link java.nio.channels.FileChannel#position()
386 * </code>position<code>} of the returned channel will be equal to the
387 * number of bytes written to the file so far unless this stream is in
388 * append mode, in which case it will be equal to the size of the file.
389 * Writing bytes to this stream will increment the channel's position
390 * accordingly. Changing the channel's position, either explicitly or by
391 * writing, will change this stream's file position.
393 * @return the file channel associated with this file output stream
398 public FileChannel getChannel() {
399 synchronized (this) {
400 if (channel == null) {
401 channel = FileChannelImpl.open(fd, false, true, append, this);
404 * Increment fd's use count. Invoking the channel's close()
405 * method will result in decrementing the use count set for
408 fd.incrementAndGetUseCount();
415 * Cleans up the connection to the file, and ensures that the
416 * <code>close</code> method of this file output stream is
417 * called when there are no more references to this stream.
419 * @exception IOException if an I/O error occurs.
420 * @see java.io.FileInputStream#close()
422 protected void finalize() throws IOException {
424 if (fd == FileDescriptor.out || fd == FileDescriptor.err) {
429 * Finalizer should not release the FileDescriptor if another
430 * stream is still using it. If the user directly invokes
431 * close() then the FileDescriptor is also released.
433 runningFinalize.set(Boolean.TRUE);
437 runningFinalize.set(Boolean.FALSE);
443 private native void close0() throws IOException;
445 private static native void initIDs();