< prev index next >

src/java.base/share/classes/java/io/FileOutputStream.java

Print this page
rev 52044 : 8192939: Remove Finalize methods from FileInputStream and FileOutputStream
   1 /*
   2  * Copyright (c) 1994, 2017, 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


  78     /**
  79      * The system dependent file descriptor.
  80      */
  81     private final FileDescriptor fd;
  82 
  83     /**
  84      * The associated channel, initialized lazily.
  85      */
  86     private volatile FileChannel channel;
  87 
  88     /**
  89      * The path of the referenced file
  90      * (null if the stream is created with a file descriptor)
  91      */
  92     private final String path;
  93 
  94     private final Object closeLock = new Object();
  95 
  96     private volatile boolean closed;
  97 
  98     private final Object altFinalizer;
  99 
 100     /**
 101      * Creates a file output stream to write to the file with the
 102      * specified name. A new <code>FileDescriptor</code> object is
 103      * created to represent this file connection.
 104      * <p>
 105      * First, if there is a security manager, its <code>checkWrite</code>
 106      * method is called with <code>name</code> as its argument.
 107      * <p>
 108      * If the file exists but is a directory rather than a regular file, does
 109      * not exist but cannot be created, or cannot be opened for any other
 110      * reason then a <code>FileNotFoundException</code> is thrown.
 111      *
 112      * @implSpec Invoking this constructor with the parameter {@code name} is
 113      * equivalent to invoking {@link #FileOutputStream(String,boolean)
 114      * new FileOutputStream(name, false)}.
 115      *
 116      * @param      name   the system-dependent filename
 117      * @exception  FileNotFoundException  if the file exists but is a directory
 118      *                   rather than a regular file, does not exist but cannot
 119      *                   be created, or cannot be opened for any other reason


 218      */
 219     public FileOutputStream(File file, boolean append)
 220         throws FileNotFoundException
 221     {
 222         String name = (file != null ? file.getPath() : null);
 223         SecurityManager security = System.getSecurityManager();
 224         if (security != null) {
 225             security.checkWrite(name);
 226         }
 227         if (name == null) {
 228             throw new NullPointerException();
 229         }
 230         if (file.isInvalid()) {
 231             throw new FileNotFoundException("Invalid file path");
 232         }
 233         this.fd = new FileDescriptor();
 234         fd.attach(this);
 235         this.path = name;
 236 
 237         open(name, append);
 238         altFinalizer = getFinalizer(this);
 239         if (altFinalizer == null) {
 240             FileCleanable.register(fd);   // open sets the fd, register the cleanup
 241         }
 242     }
 243 
 244     /**
 245      * Creates a file output stream to write to the specified file
 246      * descriptor, which represents an existing connection to an actual
 247      * file in the file system.
 248      * <p>
 249      * First, if there is a security manager, its <code>checkWrite</code>
 250      * method is called with the file descriptor <code>fdObj</code>
 251      * argument as its argument.
 252      * <p>
 253      * If <code>fdObj</code> is null then a <code>NullPointerException</code>
 254      * is thrown.
 255      * <p>
 256      * This constructor does not throw an exception if <code>fdObj</code>
 257      * is {@link java.io.FileDescriptor#valid() invalid}.
 258      * However, if the methods are invoked on the resulting stream to attempt
 259      * I/O on the stream, an <code>IOException</code> is thrown.
 260      *
 261      * @param      fdObj   the file descriptor to be opened for writing
 262      * @exception  SecurityException  if a security manager exists and its
 263      *               <code>checkWrite</code> method denies
 264      *               write access to the file descriptor
 265      * @see        java.lang.SecurityManager#checkWrite(java.io.FileDescriptor)
 266      */
 267     public FileOutputStream(FileDescriptor fdObj) {
 268         SecurityManager security = System.getSecurityManager();
 269         if (fdObj == null) {
 270             throw new NullPointerException();
 271         }
 272         if (security != null) {
 273             security.checkWrite(fdObj);
 274         }
 275         this.fd = fdObj;
 276         this.path = null;
 277         this.altFinalizer = null;
 278 
 279         fd.attach(this);
 280     }
 281 
 282     /**
 283      * Opens a file, with the specified name, for overwriting or appending.
 284      * @param name name of file to be opened
 285      * @param append whether the file is to be opened in append mode
 286      */
 287     private native void open0(String name, boolean append)
 288         throws FileNotFoundException;
 289 
 290     // wrap native call to allow instrumentation
 291     /**
 292      * Opens a file, with the specified name, for overwriting or appending.
 293      * @param name name of file to be opened
 294      * @param append whether the file is to be opened in append mode
 295      */
 296     private void open(String name, boolean append)
 297         throws FileNotFoundException {


 440             synchronized (this) {
 441                 fc = this.channel;
 442                 if (fc == null) {
 443                     this.channel = fc = FileChannelImpl.open(fd, path, false,
 444                         true, false, this);
 445                     if (closed) {
 446                         try {
 447                             // possible race with close(), benign since
 448                             // FileChannel.close is final and idempotent
 449                             fc.close();
 450                         } catch (IOException ioe) {
 451                             throw new InternalError(ioe); // should not happen
 452                         }
 453                     }
 454                 }
 455             }
 456         }
 457         return fc;
 458     }
 459 
 460     /**
 461      * Cleans up the connection to the file, and ensures that the
 462      * {@link #close} method of this file output stream is
 463      * called when there are no more references to this stream.
 464      * The {@link #finalize} method does not call {@link #close} directly.
 465      *
 466      * @apiNote
 467      * To release resources used by this stream {@link #close} should be called
 468      * directly or by try-with-resources.
 469      *
 470      * @implSpec
 471      * If this FileOutputStream has been subclassed and the {@link #close}
 472      * method has been overridden, the {@link #close} method will be
 473      * called when the FileOutputStream is unreachable.
 474      * Otherwise, it is implementation specific how the resource cleanup described in
 475      * {@link #close} is performed.
 476      *
 477      * @deprecated The {@code finalize} method has been deprecated and will be removed.
 478      *     Subclasses that override {@code finalize} in order to perform cleanup
 479      *     should be modified to use alternative cleanup mechanisms and
 480      *     to remove the overriding {@code finalize} method.
 481      *     When overriding the {@code finalize} method, its implementation must explicitly
 482      *     ensure that {@code super.finalize()} is invoked as described in {@link Object#finalize}.
 483      *     See the specification for {@link Object#finalize()} for further
 484      *     information about migration options.
 485      *
 486      * @exception  IOException  if an I/O error occurs.
 487      * @see        java.io.FileInputStream#close()
 488      */
 489     @Deprecated(since="9", forRemoval = true)
 490     protected void finalize() throws IOException {
 491     }
 492 
 493     private static native void initIDs();
 494 
 495     static {
 496         initIDs();
 497     }
 498 
 499     /*
 500      * Returns a finalizer object if the FOS needs a finalizer; otherwise null.
 501      * If the FOS has a close method; it needs an AltFinalizer.
 502      */
 503     private static Object getFinalizer(FileOutputStream fos) {
 504         Class<?> clazz = fos.getClass();
 505         while (clazz != FileOutputStream.class) {
 506             try {
 507                 clazz.getDeclaredMethod("close");
 508                 return new AltFinalizer(fos);
 509             } catch (NoSuchMethodException nsme) {
 510                 // ignore
 511             }
 512             clazz = clazz.getSuperclass();
 513         }
 514         return null;
 515     }
 516 
 517     /**
 518      * Class to call {@code FileOutputStream.close} when finalized.
 519      * If finalization of the stream is needed, an instance is created
 520      * in its constructor(s).  When the set of instances
 521      * related to the stream is unreachable, the AltFinalizer performs
 522      * the needed call to the stream's {@code close} method.
 523      */
 524     static class AltFinalizer {
 525         private final FileOutputStream fos;
 526 
 527         AltFinalizer(FileOutputStream fos) {
 528             this.fos = fos;
 529         }
 530 
 531         @Override
 532         @SuppressWarnings("deprecation")
 533         protected final void finalize() {
 534             try {
 535                 if (fos.fd != null) {
 536                     if (fos.fd == FileDescriptor.out || fos.fd == FileDescriptor.err) {
 537                         // Subclass may override flush; otherwise it is no-op
 538                         fos.flush();
 539                     } else {
 540                         /* if fd is shared, the references in FileDescriptor
 541                          * will ensure that finalizer is only called when
 542                          * safe to do so. All references using the fd have
 543                          * become unreachable. We can call close()
 544                          */
 545                         fos.close();
 546                     }
 547                 }
 548             } catch (IOException ioe) {
 549                 // ignore
 550             }
 551         }
 552     }
 553 
 554 }
   1 /*
   2  * Copyright (c) 1994, 2018, 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


  78     /**
  79      * The system dependent file descriptor.
  80      */
  81     private final FileDescriptor fd;
  82 
  83     /**
  84      * The associated channel, initialized lazily.
  85      */
  86     private volatile FileChannel channel;
  87 
  88     /**
  89      * The path of the referenced file
  90      * (null if the stream is created with a file descriptor)
  91      */
  92     private final String path;
  93 
  94     private final Object closeLock = new Object();
  95 
  96     private volatile boolean closed;
  97 


  98     /**
  99      * Creates a file output stream to write to the file with the
 100      * specified name. A new <code>FileDescriptor</code> object is
 101      * created to represent this file connection.
 102      * <p>
 103      * First, if there is a security manager, its <code>checkWrite</code>
 104      * method is called with <code>name</code> as its argument.
 105      * <p>
 106      * If the file exists but is a directory rather than a regular file, does
 107      * not exist but cannot be created, or cannot be opened for any other
 108      * reason then a <code>FileNotFoundException</code> is thrown.
 109      *
 110      * @implSpec Invoking this constructor with the parameter {@code name} is
 111      * equivalent to invoking {@link #FileOutputStream(String,boolean)
 112      * new FileOutputStream(name, false)}.
 113      *
 114      * @param      name   the system-dependent filename
 115      * @exception  FileNotFoundException  if the file exists but is a directory
 116      *                   rather than a regular file, does not exist but cannot
 117      *                   be created, or cannot be opened for any other reason


 216      */
 217     public FileOutputStream(File file, boolean append)
 218         throws FileNotFoundException
 219     {
 220         String name = (file != null ? file.getPath() : null);
 221         SecurityManager security = System.getSecurityManager();
 222         if (security != null) {
 223             security.checkWrite(name);
 224         }
 225         if (name == null) {
 226             throw new NullPointerException();
 227         }
 228         if (file.isInvalid()) {
 229             throw new FileNotFoundException("Invalid file path");
 230         }
 231         this.fd = new FileDescriptor();
 232         fd.attach(this);
 233         this.path = name;
 234 
 235         open(name, append);


 236         FileCleanable.register(fd);   // open sets the fd, register the cleanup
 237     }

 238 
 239     /**
 240      * Creates a file output stream to write to the specified file
 241      * descriptor, which represents an existing connection to an actual
 242      * file in the file system.
 243      * <p>
 244      * First, if there is a security manager, its <code>checkWrite</code>
 245      * method is called with the file descriptor <code>fdObj</code>
 246      * argument as its argument.
 247      * <p>
 248      * If <code>fdObj</code> is null then a <code>NullPointerException</code>
 249      * is thrown.
 250      * <p>
 251      * This constructor does not throw an exception if <code>fdObj</code>
 252      * is {@link java.io.FileDescriptor#valid() invalid}.
 253      * However, if the methods are invoked on the resulting stream to attempt
 254      * I/O on the stream, an <code>IOException</code> is thrown.
 255      *
 256      * @param      fdObj   the file descriptor to be opened for writing
 257      * @exception  SecurityException  if a security manager exists and its
 258      *               <code>checkWrite</code> method denies
 259      *               write access to the file descriptor
 260      * @see        java.lang.SecurityManager#checkWrite(java.io.FileDescriptor)
 261      */
 262     public FileOutputStream(FileDescriptor fdObj) {
 263         SecurityManager security = System.getSecurityManager();
 264         if (fdObj == null) {
 265             throw new NullPointerException();
 266         }
 267         if (security != null) {
 268             security.checkWrite(fdObj);
 269         }
 270         this.fd = fdObj;
 271         this.path = null;

 272 
 273         fd.attach(this);
 274     }
 275 
 276     /**
 277      * Opens a file, with the specified name, for overwriting or appending.
 278      * @param name name of file to be opened
 279      * @param append whether the file is to be opened in append mode
 280      */
 281     private native void open0(String name, boolean append)
 282         throws FileNotFoundException;
 283 
 284     // wrap native call to allow instrumentation
 285     /**
 286      * Opens a file, with the specified name, for overwriting or appending.
 287      * @param name name of file to be opened
 288      * @param append whether the file is to be opened in append mode
 289      */
 290     private void open(String name, boolean append)
 291         throws FileNotFoundException {


 434             synchronized (this) {
 435                 fc = this.channel;
 436                 if (fc == null) {
 437                     this.channel = fc = FileChannelImpl.open(fd, path, false,
 438                         true, false, this);
 439                     if (closed) {
 440                         try {
 441                             // possible race with close(), benign since
 442                             // FileChannel.close is final and idempotent
 443                             fc.close();
 444                         } catch (IOException ioe) {
 445                             throw new InternalError(ioe); // should not happen
 446                         }
 447                     }
 448                 }
 449             }
 450         }
 451         return fc;
 452     }
 453 

































 454     private static native void initIDs();
 455 
 456     static {
 457         initIDs();
 458     }
























































 459 }
< prev index next >