Class AtomicUpdateFileOutputStream

java.lang.Object
java.io.OutputStream
java.io.FileOutputStream
org.dellroad.stuff.io.AtomicUpdateFileOutputStream
All Implemented Interfaces:
Closeable, Flushable, AutoCloseable

public class AtomicUpdateFileOutputStream extends FileOutputStream
A FileOutputStream that atomically updates the target file.

Instances write to a temporary file until close() is invoked, at which time the temporary file gets renamed to the target file. This rename operation is atomic on most systems (e.g., all UNIX variants). The result is that the target file always exists, and if opened at any time, will contain either the previous content or the new content, but never a mix of the two.

Instances therefore represent a "transaction" for rewriting the file. As such, they can be in one of three states: OPEN, CLOSED, or CANCELED. State CLOSED implies that the file update was successful (no IOExceptions occurred); state CANCELED implies the file update was either explicitly canceled (via cancel()) or implicitly canceled due to an IOException being thrown by any method.

When still OPEN, the transaction is "comitted" by invoking close(), or rolled back by invoking cancel(). Once an instance has been closed or canceled, the temporary file will have been deleted, and any subsequent invocations of close() or cancel() have no effect.

Note: to guarantee that the new content will always be found in the future, even if there is a sudden system crash, the caller must also FileChannel.force(boolean) this instance (before closing) and the containing directory (after closing).

  • Field Details

    • OPEN

      public static final int OPEN
      The stream is open for writing.
      See Also:
    • CLOSED

      public static final int CLOSED
      The stream is closed and the update has been successful.
      See Also:
    • CANCELED

      public static final int CANCELED
      The stream is closed, and the update has been canceled either explicitly via cancel() or implicitly due to an IOException having been thrown.
      See Also:
  • Constructor Details

    • AtomicUpdateFileOutputStream

      public AtomicUpdateFileOutputStream(File targetFile, File tempFile) throws FileNotFoundException
      Constructor.
      Parameters:
      targetFile - the ultimate destination for the output when closed.
      tempFile - temporary file that accumulates output until close.
      Throws:
      FileNotFoundException - if tempFile cannot be opened for any reason
      SecurityException - if a security manager prevents writing to tempFile
      NullPointerException - if either parameter is null
    • AtomicUpdateFileOutputStream

      public AtomicUpdateFileOutputStream(File targetFile, File tempFile, boolean append) throws FileNotFoundException
      Constructor.
      Parameters:
      targetFile - the ultimate destination for the output when closed.
      tempFile - temporary file that accumulates output until close.
      append - if true, then bytes will be written to the end of the file rather than the beginning
      Throws:
      FileNotFoundException - if tempFile cannot be opened for any reason
      SecurityException - if a security manager prevents writing to tempFile
      NullPointerException - if either parameter is null
    • AtomicUpdateFileOutputStream

      public AtomicUpdateFileOutputStream(File targetFile) throws IOException
      Convenience constructor.

      This constructor uses a temporary file within the same directory as targetFile.

      Parameters:
      targetFile - the ultimate destination for the output when closed.
      Throws:
      FileNotFoundException - if tempFile cannot be opened for any reason
      IOException - if a temporary file could not be created
      SecurityException - if a security manager prevents writing to tempFile
      NullPointerException - if targetFile is null
    • AtomicUpdateFileOutputStream

      public AtomicUpdateFileOutputStream(File targetFile, boolean append) throws IOException
      Convenience constructor.

      This constructor uses a temporary file within the same directory as targetFile.

      Parameters:
      targetFile - the ultimate destination for the output when closed.
      append - if true, then bytes will be written to the end of the file rather than the beginning
      Throws:
      FileNotFoundException - if tempFile cannot be opened for any reason
      IOException - if a temporary file could not be created
      SecurityException - if a security manager prevents writing to tempFile
      NullPointerException - if targetFile is null
  • Method Details

    • getTargetFile

      public File getTargetFile()
      Get the target file.
      Returns:
      target file, never null
    • getTempFile

      public File getTempFile()
      Get the temporary file.

      If this instance is in state CLOSED or CANCELED, the file will no longer exist.

      Returns:
      temporary file, never null
    • getState

      public int getState()
      Get the state of this instance
      Returns:
      the current state of this instance
    • cancel

      public boolean cancel()
      Cancel this instance if still open. This rolls back the open transaction.

      This method does nothing (and returns false) if close() or cancel() has already been invoked.

      Returns:
      true if this instance was canceled, false if this instance is already closed or canceled
    • write

      public void write(byte[] b) throws IOException
      Overrides:
      write in class FileOutputStream
      Throws:
      IOException
    • write

      public void write(byte[] b, int off, int len) throws IOException
      Overrides:
      write in class FileOutputStream
      Throws:
      IOException
    • write

      public void write(int b) throws IOException
      Overrides:
      write in class FileOutputStream
      Throws:
      IOException
    • flush

      public void flush() throws IOException
      Specified by:
      flush in interface Flushable
      Overrides:
      flush in class OutputStream
      Throws:
      IOException
    • close

      public void close() throws IOException
      Close this instance if still open. This commits the open transaction.

      If this instance is still open, this method will close the temporary file and then attempt to atomically rename it onto the target file. In any case, after this method returns (either normally or abnormally), the temporary file will no longer exist.

      If this instance has already been closed or canceled, this method does nothing.

      Specified by:
      close in interface AutoCloseable
      Specified by:
      close in interface Closeable
      Overrides:
      close in class FileOutputStream
      Throws:
      IOException - if an I/O error occurs
    • getTimestamp

      public long getTimestamp()
      Get the last modification timestamp of the target file as it was at the time it was updated by this instance.

      This method only works after close() has been successfully invoked, otherwise it returns zero.

      Returns:
      target file modification time, or zero if close() has not been successfully invoked
    • finalize

      protected void finalize() throws Throwable
      Ensure the temporary file is deleted in cases where this instance never got successfully closed.
      Overrides:
      finalize in class Object
      Throws:
      Throwable