rt/emul/compact/src/main/java/java/io/FileOutputStream.java
author Jaroslav Tulach <jtulach@netbeans.org>
Thu, 03 Oct 2013 15:40:35 +0200
branchjdk7-b147
changeset 1334 588d5bf7a560
child 1337 c794024954b5
permissions -rw-r--r--
Set of JDK classes needed to run javac
     1 /*
     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.
     4  *
     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.
    10  *
    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).
    16  *
    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.
    20  *
    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
    23  * questions.
    24  */
    25 
    26 package java.io;
    27 
    28 import java.nio.channels.FileChannel;
    29 import sun.nio.ch.FileChannelImpl;
    30 
    31 
    32 /**
    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.
    40  *
    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>.
    44  *
    45  * @author  Arthur van Hoff
    46  * @see     java.io.File
    47  * @see     java.io.FileDescriptor
    48  * @see     java.io.FileInputStream
    49  * @see     java.nio.file.Files#newOutputStream
    50  * @since   JDK1.0
    51  */
    52 public
    53 class FileOutputStream extends OutputStream
    54 {
    55     /**
    56      * The system dependent file descriptor.
    57      */
    58     private final FileDescriptor fd;
    59 
    60     /**
    61      * True if the file is opened for append.
    62      */
    63     private final boolean append;
    64 
    65     /**
    66      * The associated channel, initalized lazily.
    67      */
    68     private FileChannel channel;
    69 
    70     private final Object closeLock = new Object();
    71     private volatile boolean closed = false;
    72     private static final ThreadLocal<Boolean> runningFinalize =
    73         new ThreadLocal<>();
    74 
    75     private static boolean isRunningFinalize() {
    76         Boolean val;
    77         if ((val = runningFinalize.get()) != null)
    78             return val.booleanValue();
    79         return false;
    80     }
    81 
    82     /**
    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.
    86      * <p>
    87      * First, if there is a security manager, its <code>checkWrite</code>
    88      * method is called with <code>name</code> as its argument.
    89      * <p>
    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.
    93      *
    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
   100      *               to the file.
   101      * @see        java.lang.SecurityManager#checkWrite(java.lang.String)
   102      */
   103     public FileOutputStream(String name) throws FileNotFoundException {
   104         this(name != null ? new File(name) : null, false);
   105     }
   106 
   107     /**
   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
   112      * file connection.
   113      * <p>
   114      * First, if there is a security manager, its <code>checkWrite</code>
   115      * method is called with <code>name</code> as its argument.
   116      * <p>
   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.
   120      *
   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
   129      *               to the file.
   130      * @see        java.lang.SecurityManager#checkWrite(java.lang.String)
   131      * @since     JDK1.1
   132      */
   133     public FileOutputStream(String name, boolean append)
   134         throws FileNotFoundException
   135     {
   136         this(name != null ? new File(name) : null, append);
   137     }
   138 
   139     /**
   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
   143      * file connection.
   144      * <p>
   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.
   148      * <p>
   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.
   152      *
   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
   159      *               to the file.
   160      * @see        java.io.File#getPath()
   161      * @see        java.lang.SecurityException
   162      * @see        java.lang.SecurityManager#checkWrite(java.lang.String)
   163      */
   164     public FileOutputStream(File file) throws FileNotFoundException {
   165         this(file, false);
   166     }
   167 
   168     /**
   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.
   174      * <p>
   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.
   178      * <p>
   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.
   182      *
   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
   191      *               to the file.
   192      * @see        java.io.File#getPath()
   193      * @see        java.lang.SecurityException
   194      * @see        java.lang.SecurityManager#checkWrite(java.lang.String)
   195      * @since 1.4
   196      */
   197     public FileOutputStream(File file, boolean append)
   198         throws FileNotFoundException
   199     {
   200         String name = (file != null ? file.getPath() : null);
   201         SecurityManager security = System.getSecurityManager();
   202         if (security != null) {
   203             security.checkWrite(name);
   204         }
   205         if (name == null) {
   206             throw new NullPointerException();
   207         }
   208         this.fd = new FileDescriptor();
   209         this.append = append;
   210 
   211         fd.incrementAndGetUseCount();
   212         open(name, append);
   213     }
   214 
   215     /**
   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.
   219      * <p>
   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.
   223      * <p>
   224      * If <code>fdObj</code> is null then a <code>NullPointerException</code>
   225      * is thrown.
   226      * <p>
   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.
   231      *
   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)
   237      */
   238     public FileOutputStream(FileDescriptor fdObj) {
   239         SecurityManager security = System.getSecurityManager();
   240         if (fdObj == null) {
   241             throw new NullPointerException();
   242         }
   243         if (security != null) {
   244             security.checkWrite(fdObj);
   245         }
   246         this.fd = fdObj;
   247         this.append = false;
   248 
   249         /*
   250          * FileDescriptor is being shared by streams.
   251          * Ensure that it's GC'ed only when all the streams/channels are done
   252          * using it.
   253          */
   254         fd.incrementAndGetUseCount();
   255     }
   256 
   257     /**
   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
   261      */
   262     private native void open(String name, boolean append)
   263         throws FileNotFoundException;
   264 
   265     /**
   266      * Writes the specified byte to this file output stream.
   267      *
   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
   271      */
   272     private native void write(int b, boolean append) throws IOException;
   273 
   274     /**
   275      * Writes the specified byte to this file output stream. Implements
   276      * the <code>write</code> method of <code>OutputStream</code>.
   277      *
   278      * @param      b   the byte to be written.
   279      * @exception  IOException  if an I/O error occurs.
   280      */
   281     public void write(int b) throws IOException {
   282         write(b, append);
   283     }
   284 
   285     /**
   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
   291      *     end of file
   292      * @exception IOException If an I/O error has occurred.
   293      */
   294     private native void writeBytes(byte b[], int off, int len, boolean append)
   295         throws IOException;
   296 
   297     /**
   298      * Writes <code>b.length</code> bytes from the specified byte array
   299      * to this file output stream.
   300      *
   301      * @param      b   the data.
   302      * @exception  IOException  if an I/O error occurs.
   303      */
   304     public void write(byte b[]) throws IOException {
   305         writeBytes(b, 0, b.length, append);
   306     }
   307 
   308     /**
   309      * Writes <code>len</code> bytes from the specified byte array
   310      * starting at offset <code>off</code> to this file output stream.
   311      *
   312      * @param      b     the data.
   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.
   316      */
   317     public void write(byte b[], int off, int len) throws IOException {
   318         writeBytes(b, off, len, append);
   319     }
   320 
   321     /**
   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.
   325      *
   326      * <p> If this stream has an associated channel then the channel is closed
   327      * as well.
   328      *
   329      * @exception  IOException  if an I/O error occurs.
   330      *
   331      * @revised 1.4
   332      * @spec JSR-51
   333      */
   334     public void close() throws IOException {
   335         synchronized (closeLock) {
   336             if (closed) {
   337                 return;
   338             }
   339             closed = true;
   340         }
   341 
   342         if (channel != null) {
   343             /*
   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.
   347              */
   348             fd.decrementAndGetUseCount();
   349             channel.close();
   350         }
   351 
   352         /*
   353          * Decrement FD use count associated with this stream
   354          */
   355         int useCount = fd.decrementAndGetUseCount();
   356 
   357         /*
   358          * If FileDescriptor is still in use by another stream, the finalizer
   359          * will not close it.
   360          */
   361         if ((useCount <= 0) || !isRunningFinalize()) {
   362             close0();
   363         }
   364     }
   365 
   366     /**
   367      * Returns the file descriptor associated with this stream.
   368      *
   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.
   372      *
   373      * @exception  IOException  if an I/O error occurs.
   374      * @see        java.io.FileDescriptor
   375      */
   376      public final FileDescriptor getFD()  throws IOException {
   377         if (fd != null) return fd;
   378         throw new IOException();
   379      }
   380 
   381     /**
   382      * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
   383      * object associated with this file output stream. </p>
   384      *
   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.
   392      *
   393      * @return  the file channel associated with this file output stream
   394      *
   395      * @since 1.4
   396      * @spec JSR-51
   397      */
   398     public FileChannel getChannel() {
   399         synchronized (this) {
   400             if (channel == null) {
   401                 channel = FileChannelImpl.open(fd, false, true, append, this);
   402 
   403                 /*
   404                  * Increment fd's use count. Invoking the channel's close()
   405                  * method will result in decrementing the use count set for
   406                  * the channel.
   407                  */
   408                 fd.incrementAndGetUseCount();
   409             }
   410             return channel;
   411         }
   412     }
   413 
   414     /**
   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.
   418      *
   419      * @exception  IOException  if an I/O error occurs.
   420      * @see        java.io.FileInputStream#close()
   421      */
   422     protected void finalize() throws IOException {
   423         if (fd != null) {
   424             if (fd == FileDescriptor.out || fd == FileDescriptor.err) {
   425                 flush();
   426             } else {
   427 
   428                 /*
   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.
   432                  */
   433                 runningFinalize.set(Boolean.TRUE);
   434                 try {
   435                     close();
   436                 } finally {
   437                     runningFinalize.set(Boolean.FALSE);
   438                 }
   439             }
   440         }
   441     }
   442 
   443     private native void close0() throws IOException;
   444 
   445     private static native void initIDs();
   446 
   447     static {
   448         initIDs();
   449     }
   450 
   451 }