1. /*
  2. * Copyright 2001-2004 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.apache.commons.io.output;
  17. import java.io.ByteArrayOutputStream;
  18. import java.io.File;
  19. import java.io.FileOutputStream;
  20. import java.io.IOException;
  21. import java.io.OutputStream;
  22. /**
  23. * <p>An output stream which will retain data in memory until a specified
  24. * threshold is reached, and only then commit it to disk. If the stream is
  25. * closed before the threshold is reached, the data will not be written to
  26. * disk at all.</p>
  27. *
  28. * @author <a href="mailto:martinc@apache.org">Martin Cooper</a>
  29. *
  30. * @version $Id: DeferredFileOutputStream.java,v 1.2 2004/02/23 04:40:29 bayard Exp $
  31. */
  32. public class DeferredFileOutputStream
  33. extends ThresholdingOutputStream
  34. {
  35. // ----------------------------------------------------------- Data members
  36. /**
  37. * The output stream to which data will be written prior to the theshold
  38. * being reached.
  39. */
  40. private ByteArrayOutputStream memoryOutputStream;
  41. /**
  42. * The output stream to which data will be written after the theshold is
  43. * reached.
  44. */
  45. private FileOutputStream diskOutputStream;
  46. /**
  47. * The output stream to which data will be written at any given time. This
  48. * will always be one of <code>memoryOutputStream</code> or
  49. * <code>diskOutputStream</code>.
  50. */
  51. private OutputStream currentOutputStream;
  52. /**
  53. * The file to which output will be directed if the threshold is exceeded.
  54. */
  55. private File outputFile;
  56. // ----------------------------------------------------------- Constructors
  57. /**
  58. * Constructs an instance of this class which will trigger an event at the
  59. * specified threshold, and save data to a file beyond that point.
  60. *
  61. * @param threshold The number of bytes at which to trigger an event.
  62. * @param outputFile The file to which data is saved beyond the threshold.
  63. */
  64. public DeferredFileOutputStream(int threshold, File outputFile)
  65. {
  66. super(threshold);
  67. this.outputFile = outputFile;
  68. memoryOutputStream = new ByteArrayOutputStream(threshold);
  69. currentOutputStream = memoryOutputStream;
  70. }
  71. // --------------------------------------- ThresholdingOutputStream methods
  72. /**
  73. * Returns the current output stream. This may be memory based or disk
  74. * based, depending on the current state with respect to the threshold.
  75. *
  76. * @return The underlying output stream.
  77. *
  78. * @exception IOException if an error occurs.
  79. */
  80. protected OutputStream getStream() throws IOException
  81. {
  82. return currentOutputStream;
  83. }
  84. /**
  85. * Switches the underlying output stream from a memory based stream to one
  86. * that is backed by disk. This is the point at which we realise that too
  87. * much data is being written to keep in memory, so we elect to switch to
  88. * disk-based storage.
  89. *
  90. * @exception IOException if an error occurs.
  91. */
  92. protected void thresholdReached() throws IOException
  93. {
  94. byte[] data = memoryOutputStream.toByteArray();
  95. FileOutputStream fos = new FileOutputStream(outputFile);
  96. fos.write(data);
  97. diskOutputStream = fos;
  98. currentOutputStream = fos;
  99. memoryOutputStream = null;
  100. }
  101. // --------------------------------------------------------- Public methods
  102. /**
  103. * Determines whether or not the data for this output stream has been
  104. * retained in memory.
  105. *
  106. * @return <code>true</code> if the data is available in memory;
  107. * <code>false</code> otherwise.
  108. */
  109. public boolean isInMemory()
  110. {
  111. return (!isThresholdExceeded());
  112. }
  113. /**
  114. * Returns the data for this output stream as an array of bytes, assuming
  115. * that the data has been retained in memory. If the data was written to
  116. * disk, this method returns <code>null</code>.
  117. *
  118. * @return The data for this output stream, or <code>null</code> if no such
  119. * data is available.
  120. */
  121. public byte[] getData()
  122. {
  123. if (memoryOutputStream != null)
  124. {
  125. return memoryOutputStream.toByteArray();
  126. }
  127. return null;
  128. }
  129. /**
  130. * Returns the data for this output stream as a <code>File</code>, assuming
  131. * that the data was written to disk. If the data was retained in memory,
  132. * this method returns <code>null</code>.
  133. *
  134. * @return The file for this output stream, or <code>null</code> if no such
  135. * file exists.
  136. */
  137. public File getFile()
  138. {
  139. return outputFile;
  140. }
  141. }