rt/emul/compact/src/main/java/java/io/FileOutputStream.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Thu, 03 Oct 2013 17:36:44 +0200
changeset 1337 c794024954b5
parent 1334 588d5bf7a560
permissions -rw-r--r--
Implementation of few more JDK classes
     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 
    29 
    30 /**
    31  * A file output stream is an output stream for writing data to a
    32  * <code>File</code> or to a <code>FileDescriptor</code>. Whether or not
    33  * a file is available or may be created depends upon the underlying
    34  * platform.  Some platforms, in particular, allow a file to be opened
    35  * for writing by only one <tt>FileOutputStream</tt> (or other
    36  * file-writing object) at a time.  In such situations the constructors in
    37  * this class will fail if the file involved is already open.
    38  *
    39  * <p><code>FileOutputStream</code> is meant for writing streams of raw bytes
    40  * such as image data. For writing streams of characters, consider using
    41  * <code>FileWriter</code>.
    42  *
    43  * @author  Arthur van Hoff
    44  * @see     java.io.File
    45  * @see     java.io.FileDescriptor
    46  * @see     java.io.FileInputStream
    47  * @see     java.nio.file.Files#newOutputStream
    48  * @since   JDK1.0
    49  */
    50 public
    51 class FileOutputStream extends OutputStream
    52 {
    53     /**
    54      * The system dependent file descriptor.
    55      */
    56     private final FileDescriptor fd;
    57 
    58     /**
    59      * True if the file is opened for append.
    60      */
    61     private final boolean append;
    62 
    63     /**
    64      * The associated channel, initalized lazily.
    65      */
    66 //    private FileChannel channel;
    67 
    68     private final Object closeLock = new Object();
    69     private volatile boolean closed = false;
    70     private static final ThreadLocal<Boolean> runningFinalize =
    71         new ThreadLocal<>();
    72 
    73     private static boolean isRunningFinalize() {
    74         Boolean val;
    75         if ((val = runningFinalize.get()) != null)
    76             return val.booleanValue();
    77         return false;
    78     }
    79 
    80     /**
    81      * Creates a file output stream to write to the file with the
    82      * specified name. A new <code>FileDescriptor</code> object is
    83      * created to represent this file connection.
    84      * <p>
    85      * First, if there is a security manager, its <code>checkWrite</code>
    86      * method is called with <code>name</code> as its argument.
    87      * <p>
    88      * If the file exists but is a directory rather than a regular file, does
    89      * not exist but cannot be created, or cannot be opened for any other
    90      * reason then a <code>FileNotFoundException</code> is thrown.
    91      *
    92      * @param      name   the system-dependent filename
    93      * @exception  FileNotFoundException  if the file exists but is a directory
    94      *                   rather than a regular file, does not exist but cannot
    95      *                   be created, or cannot be opened for any other reason
    96      * @exception  SecurityException  if a security manager exists and its
    97      *               <code>checkWrite</code> method denies write access
    98      *               to the file.
    99      * @see        java.lang.SecurityManager#checkWrite(java.lang.String)
   100      */
   101     public FileOutputStream(String name) throws FileNotFoundException {
   102         this(name != null ? new File(name) : null, false);
   103     }
   104 
   105     /**
   106      * Creates a file output stream to write to the file with the specified
   107      * name.  If the second argument is <code>true</code>, then
   108      * bytes will be written to the end of the file rather than the beginning.
   109      * A new <code>FileDescriptor</code> object is created to represent this
   110      * file connection.
   111      * <p>
   112      * First, if there is a security manager, its <code>checkWrite</code>
   113      * method is called with <code>name</code> as its argument.
   114      * <p>
   115      * If the file exists but is a directory rather than a regular file, does
   116      * not exist but cannot be created, or cannot be opened for any other
   117      * reason then a <code>FileNotFoundException</code> is thrown.
   118      *
   119      * @param     name        the system-dependent file name
   120      * @param     append      if <code>true</code>, then bytes will be written
   121      *                   to the end of the file rather than the beginning
   122      * @exception  FileNotFoundException  if the file exists but is a directory
   123      *                   rather than a regular file, does not exist but cannot
   124      *                   be created, or cannot be opened for any other reason.
   125      * @exception  SecurityException  if a security manager exists and its
   126      *               <code>checkWrite</code> method denies write access
   127      *               to the file.
   128      * @see        java.lang.SecurityManager#checkWrite(java.lang.String)
   129      * @since     JDK1.1
   130      */
   131     public FileOutputStream(String name, boolean append)
   132         throws FileNotFoundException
   133     {
   134         this(name != null ? new File(name) : null, append);
   135     }
   136 
   137     /**
   138      * Creates a file output stream to write to the file represented by
   139      * the specified <code>File</code> object. A new
   140      * <code>FileDescriptor</code> object is created to represent this
   141      * file connection.
   142      * <p>
   143      * First, if there is a security manager, its <code>checkWrite</code>
   144      * method is called with the path represented by the <code>file</code>
   145      * argument as its argument.
   146      * <p>
   147      * If the file exists but is a directory rather than a regular file, does
   148      * not exist but cannot be created, or cannot be opened for any other
   149      * reason then a <code>FileNotFoundException</code> is thrown.
   150      *
   151      * @param      file               the file to be opened for writing.
   152      * @exception  FileNotFoundException  if the file exists but is a directory
   153      *                   rather than a regular file, does not exist but cannot
   154      *                   be created, or cannot be opened for any other reason
   155      * @exception  SecurityException  if a security manager exists and its
   156      *               <code>checkWrite</code> method denies write access
   157      *               to the file.
   158      * @see        java.io.File#getPath()
   159      * @see        java.lang.SecurityException
   160      * @see        java.lang.SecurityManager#checkWrite(java.lang.String)
   161      */
   162     public FileOutputStream(File file) throws FileNotFoundException {
   163         this(file, false);
   164     }
   165 
   166     /**
   167      * Creates a file output stream to write to the file represented by
   168      * the specified <code>File</code> object. If the second argument is
   169      * <code>true</code>, then bytes will be written to the end of the file
   170      * rather than the beginning. A new <code>FileDescriptor</code> object is
   171      * created to represent this file connection.
   172      * <p>
   173      * First, if there is a security manager, its <code>checkWrite</code>
   174      * method is called with the path represented by the <code>file</code>
   175      * argument as its argument.
   176      * <p>
   177      * If the file exists but is a directory rather than a regular file, does
   178      * not exist but cannot be created, or cannot be opened for any other
   179      * reason then a <code>FileNotFoundException</code> is thrown.
   180      *
   181      * @param      file               the file to be opened for writing.
   182      * @param     append      if <code>true</code>, then bytes will be written
   183      *                   to the end of the file rather than the beginning
   184      * @exception  FileNotFoundException  if the file exists but is a directory
   185      *                   rather than a regular file, does not exist but cannot
   186      *                   be created, or cannot be opened for any other reason
   187      * @exception  SecurityException  if a security manager exists and its
   188      *               <code>checkWrite</code> method denies write access
   189      *               to the file.
   190      * @see        java.io.File#getPath()
   191      * @see        java.lang.SecurityException
   192      * @see        java.lang.SecurityManager#checkWrite(java.lang.String)
   193      * @since 1.4
   194      */
   195     public FileOutputStream(File file, boolean append)
   196         throws FileNotFoundException
   197     {
   198         throw new SecurityException();
   199     }
   200 
   201     /**
   202      * Creates a file output stream to write to the specified file
   203      * descriptor, which represents an existing connection to an actual
   204      * file in the file system.
   205      * <p>
   206      * First, if there is a security manager, its <code>checkWrite</code>
   207      * method is called with the file descriptor <code>fdObj</code>
   208      * argument as its argument.
   209      * <p>
   210      * If <code>fdObj</code> is null then a <code>NullPointerException</code>
   211      * is thrown.
   212      * <p>
   213      * This constructor does not throw an exception if <code>fdObj</code>
   214      * is {@link java.io.FileDescriptor#valid() invalid}.
   215      * However, if the methods are invoked on the resulting stream to attempt
   216      * I/O on the stream, an <code>IOException</code> is thrown.
   217      *
   218      * @param      fdObj   the file descriptor to be opened for writing
   219      * @exception  SecurityException  if a security manager exists and its
   220      *               <code>checkWrite</code> method denies
   221      *               write access to the file descriptor
   222      * @see        java.lang.SecurityManager#checkWrite(java.io.FileDescriptor)
   223      */
   224     public FileOutputStream(FileDescriptor fdObj) {
   225         throw new SecurityException();
   226     }
   227 
   228     /**
   229      * Opens a file, with the specified name, for overwriting or appending.
   230      * @param name name of file to be opened
   231      * @param append whether the file is to be opened in append mode
   232      */
   233     private native void open(String name, boolean append)
   234         throws FileNotFoundException;
   235 
   236     /**
   237      * Writes the specified byte to this file output stream.
   238      *
   239      * @param   b   the byte to be written.
   240      * @param   append   {@code true} if the write operation first
   241      *     advances the position to the end of file
   242      */
   243     private native void write(int b, boolean append) throws IOException;
   244 
   245     /**
   246      * Writes the specified byte to this file output stream. Implements
   247      * the <code>write</code> method of <code>OutputStream</code>.
   248      *
   249      * @param      b   the byte to be written.
   250      * @exception  IOException  if an I/O error occurs.
   251      */
   252     public void write(int b) throws IOException {
   253         write(b, append);
   254     }
   255 
   256     /**
   257      * Writes a sub array as a sequence of bytes.
   258      * @param b the data to be written
   259      * @param off the start offset in the data
   260      * @param len the number of bytes that are written
   261      * @param append {@code true} to first advance the position to the
   262      *     end of file
   263      * @exception IOException If an I/O error has occurred.
   264      */
   265     private native void writeBytes(byte b[], int off, int len, boolean append)
   266         throws IOException;
   267 
   268     /**
   269      * Writes <code>b.length</code> bytes from the specified byte array
   270      * to this file output stream.
   271      *
   272      * @param      b   the data.
   273      * @exception  IOException  if an I/O error occurs.
   274      */
   275     public void write(byte b[]) throws IOException {
   276         writeBytes(b, 0, b.length, append);
   277     }
   278 
   279     /**
   280      * Writes <code>len</code> bytes from the specified byte array
   281      * starting at offset <code>off</code> to this file output stream.
   282      *
   283      * @param      b     the data.
   284      * @param      off   the start offset in the data.
   285      * @param      len   the number of bytes to write.
   286      * @exception  IOException  if an I/O error occurs.
   287      */
   288     public void write(byte b[], int off, int len) throws IOException {
   289         writeBytes(b, off, len, append);
   290     }
   291 
   292     /**
   293      * Closes this file output stream and releases any system resources
   294      * associated with this stream. This file output stream may no longer
   295      * be used for writing bytes.
   296      *
   297      * <p> If this stream has an associated channel then the channel is closed
   298      * as well.
   299      *
   300      * @exception  IOException  if an I/O error occurs.
   301      *
   302      * @revised 1.4
   303      * @spec JSR-51
   304      */
   305     public void close() throws IOException {
   306         synchronized (closeLock) {
   307             if (closed) {
   308                 return;
   309             }
   310             closed = true;
   311         }
   312 //
   313 //        if (channel != null) {
   314 //            /*
   315 //             * Decrement FD use count associated with the channel
   316 //             * The use count is incremented whenever a new channel
   317 //             * is obtained from this stream.
   318 //             */
   319 //            fd.decrementAndGetUseCount();
   320 //            channel.close();
   321 //        }
   322 
   323         /*
   324          * Decrement FD use count associated with this stream
   325          */
   326         int useCount = fd.decrementAndGetUseCount();
   327 
   328         /*
   329          * If FileDescriptor is still in use by another stream, the finalizer
   330          * will not close it.
   331          */
   332         if ((useCount <= 0) || !isRunningFinalize()) {
   333             close0();
   334         }
   335     }
   336 
   337     /**
   338      * Returns the file descriptor associated with this stream.
   339      *
   340      * @return  the <code>FileDescriptor</code> object that represents
   341      *          the connection to the file in the file system being used
   342      *          by this <code>FileOutputStream</code> object.
   343      *
   344      * @exception  IOException  if an I/O error occurs.
   345      * @see        java.io.FileDescriptor
   346      */
   347      public final FileDescriptor getFD()  throws IOException {
   348         if (fd != null) return fd;
   349         throw new IOException();
   350      }
   351 
   352     /**
   353      * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
   354      * object associated with this file output stream. </p>
   355      *
   356      * <p> The initial {@link java.nio.channels.FileChannel#position()
   357      * </code>position<code>} of the returned channel will be equal to the
   358      * number of bytes written to the file so far unless this stream is in
   359      * append mode, in which case it will be equal to the size of the file.
   360      * Writing bytes to this stream will increment the channel's position
   361      * accordingly.  Changing the channel's position, either explicitly or by
   362      * writing, will change this stream's file position.
   363      *
   364      * @return  the file channel associated with this file output stream
   365      *
   366      * @since 1.4
   367      * @spec JSR-51
   368      */
   369 //    public FileChannel getChannel() {
   370 //        synchronized (this) {
   371 //            if (channel == null) {
   372 //                channel = FileChannelImpl.open(fd, false, true, append, this);
   373 //
   374 //                /*
   375 //                 * Increment fd's use count. Invoking the channel's close()
   376 //                 * method will result in decrementing the use count set for
   377 //                 * the channel.
   378 //                 */
   379 //                fd.incrementAndGetUseCount();
   380 //            }
   381 //            return channel;
   382 //        }
   383 //    }
   384 
   385     /**
   386      * Cleans up the connection to the file, and ensures that the
   387      * <code>close</code> method of this file output stream is
   388      * called when there are no more references to this stream.
   389      *
   390      * @exception  IOException  if an I/O error occurs.
   391      * @see        java.io.FileInputStream#close()
   392      */
   393     protected void finalize() throws IOException {
   394         if (fd != null) {
   395             if (fd == FileDescriptor.out || fd == FileDescriptor.err) {
   396                 flush();
   397             } else {
   398 
   399                 /*
   400                  * Finalizer should not release the FileDescriptor if another
   401                  * stream is still using it. If the user directly invokes
   402                  * close() then the FileDescriptor is also released.
   403                  */
   404                 runningFinalize.set(Boolean.TRUE);
   405                 try {
   406                     close();
   407                 } finally {
   408                     runningFinalize.set(Boolean.FALSE);
   409                 }
   410             }
   411         }
   412     }
   413 
   414     private native void close0() throws IOException;
   415 
   416     private static native void initIDs();
   417 
   418     static {
   419         initIDs();
   420     }
   421 
   422 }