Java/File Input Output/ByteArrayOutputStream

Материал из Java эксперт
Перейти к: навигация, поиск

An unsynchronized version of java.io.ByteArrayOutputStream

   <source lang="java">
   

/* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved.

* 
* This program and the accompanying materials are made available under
* the terms of the Common Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/cpl-v10.html
* 
* $Id: ByteArrayOStream.java,v 1.1.1.1 2004/05/09 16:57:52 vlad_r Exp $
*/

import java.io.IOException; import java.io.OutputStream;

// ---------------------------------------------------------------------------- /**

* An unsynchronized version of java.io.ByteArrayOutputStream that can expose
* the underlying byte array without a defensive clone and can also be converted
* to a {@link ByteArrayIStream} without intermediate array copies.

* * All argument validation is disabled in release mode.<p> * * NOTE: copy-on-write not supported * * @author (C) 2001, Vlad Roubtsov */ public final class ByteArrayOStream extends OutputStream { // public: ................................................................ /** * Callee takes ownership of "buf". */ public ByteArrayOStream (final int initialCapacity) { m_buf = new byte [initialCapacity]; } public final void write2 (final int b1, final int b2) { final int pos = m_pos; final int capacity = pos + 2; byte [] mbuf = m_buf; final int mbuflen = mbuf.length; if (mbuflen < capacity) { final byte [] newbuf = new byte [Math.max (mbuflen << 1, capacity)]; if (pos < NATIVE_COPY_THRESHOLD) for (int i = 0; i < pos; ++ i) newbuf [i] = mbuf [i]; else System.arraycopy (mbuf, 0, newbuf, 0, pos); m_buf = mbuf = newbuf; } mbuf [pos] = (byte) b1; mbuf [pos + 1] = (byte) b2; m_pos = capacity; } public final void write3 (final int b1, final int b2, final int b3) { final int pos = m_pos; final int capacity = pos + 3; byte [] mbuf = m_buf; final int mbuflen = mbuf.length; if (mbuflen < capacity) { final byte [] newbuf = new byte [Math.max (mbuflen << 1, capacity)]; if (pos < NATIVE_COPY_THRESHOLD) for (int i = 0; i < pos; ++ i) newbuf [i] = mbuf [i]; else System.arraycopy (mbuf, 0, newbuf, 0, pos); m_buf = mbuf = newbuf; } mbuf [pos] = (byte) b1; mbuf [pos + 1] = (byte) b2; mbuf [pos + 2] = (byte) b3; m_pos = capacity; } public final void write4 (final int b1, final int b2, final int b3, final int b4) { final int pos = m_pos; final int capacity = pos + 4; byte [] mbuf = m_buf; final int mbuflen = mbuf.length; if (mbuflen < capacity) { final byte [] newbuf = new byte [Math.max (mbuflen << 1, capacity)]; if (pos < NATIVE_COPY_THRESHOLD) for (int i = 0; i < pos; ++ i) newbuf [i] = mbuf [i]; else System.arraycopy (mbuf, 0, newbuf, 0, pos); m_buf = mbuf = newbuf; } mbuf [pos] = (byte) b1; mbuf [pos + 1] = (byte) b2; mbuf [pos + 2] = (byte) b3; mbuf [pos + 3] = (byte) b4; m_pos = capacity; } public final void writeTo (final OutputStream out) throws IOException { out.write (m_buf, 0, m_pos); } // public final void readFully (final InputStream in) // throws IOException // { // while (true) // { // int chunk = in.available (); // // System.out.println ("available = " + chunk); // // // TODO: this case is handled poorly (on EOF) // if (chunk == 0) chunk = READ_CHUNK_SIZE; // // // read at least "available" bytes: extend the capacity as needed // // int free = m_buf.length - m_pos; // // final int read; // if (free > chunk) // { // // try reading more than "chunk" anyway: // read = in.read (m_buf, m_pos, free); // } // else // { // // extend the capacity to match "chunk": // { // System.out.println ("reallocation"); // final byte [] newbuf = new byte [m_pos + chunk]; // // if (m_pos < NATIVE_COPY_THRESHOLD) // for (int i = 0; i < m_pos; ++ i) newbuf [i] = m_buf [i]; // else // System.arraycopy (m_buf, 0, newbuf, 0, m_pos); // // m_buf = newbuf; // } // // read = in.read (m_buf, m_pos, chunk); // } // // if (read < 0) // break; // else // m_pos += read; // } // } // public final void addCapacity (final int extraCapacity) // { // final int pos = m_pos; // final int capacity = pos + extraCapacity; // byte [] mbuf = m_buf; // final int mbuflen = mbuf.length; // // if (mbuflen < capacity) // { // final byte [] newbuf = new byte [Math.max (mbuflen << 1, capacity)]; // // if (pos < NATIVE_COPY_THRESHOLD) // for (int i = 0; i < pos; ++ i) newbuf [i] = mbuf [i]; // else // System.arraycopy (mbuf, 0, newbuf, 0, pos); // // m_buf = newbuf; // } // } public final byte [] getByteArray () { return m_buf; } /** * * @return [result.length = size()] */ public final byte [] copyByteArray () { final int pos = m_pos; final byte [] result = new byte [pos]; final byte [] mbuf = m_buf; if (pos < NATIVE_COPY_THRESHOLD) for (int i = 0; i < pos; ++ i) result [i] = mbuf [i]; else System.arraycopy (mbuf, 0, result, 0, pos); return result; } public final int size () { return m_pos; } public final int capacity () { return m_buf.length; } /** * Does not reduce the current capacity. */ public final void reset () { m_pos = 0; } // OutputStream: public final void write (final int b) { final int pos = m_pos; final int capacity = pos + 1; byte [] mbuf = m_buf; final int mbuflen = mbuf.length; if (mbuflen < capacity) { final byte [] newbuf = new byte [Math.max (mbuflen << 1, capacity)]; if (pos < NATIVE_COPY_THRESHOLD) for (int i = 0; i < pos; ++ i) newbuf [i] = mbuf [i]; else System.arraycopy (mbuf, 0, newbuf, 0, pos); m_buf = mbuf = newbuf; } mbuf [pos] = (byte) b; m_pos = capacity; } public final void write (final byte [] buf, final int offset, final int length) { final int pos = m_pos; final int capacity = pos + length; byte [] mbuf = m_buf; final int mbuflen = mbuf.length; if (mbuflen < capacity) { final byte [] newbuf = new byte [Math.max (mbuflen << 1, capacity)]; if (pos < NATIVE_COPY_THRESHOLD) for (int i = 0; i < pos; ++ i) newbuf [i] = mbuf [i]; else System.arraycopy (mbuf, 0, newbuf, 0, pos); m_buf = mbuf = newbuf; } if (length < NATIVE_COPY_THRESHOLD) for (int i = 0; i < length; ++ i) mbuf [pos + i] = buf [offset + i]; else System.arraycopy (buf, offset, mbuf, pos, length); m_pos = capacity; } /** * Equivalent to {@link #reset()}. */ public final void close () { reset (); } // protected: ............................................................. // package: ............................................................... // private: ............................................................... private byte [] m_buf; private int m_pos; // private static final int READ_CHUNK_SIZE = 16 * 1024; private static final int NATIVE_COPY_THRESHOLD = 9; } // end of class // ---------------------------------------------------------------------------- </source>

A speedy implementation of ByteArrayOutputStream.

   <source lang="java">
   

/*

* Copyright (c) 2002-2003 by OpenSymphony
* All rights reserved.
*/

import java.io.IOException; import java.io.OutputStream; import java.io.RandomAccessFile; import java.io.Writer; import java.util.Iterator; import java.util.LinkedList;

/**

* A speedy implementation of ByteArrayOutputStream. It"s not synchronized, and it
* does not copy buffers when it"s expanded. There"s also no copying of the internal buffer
* if it"s contents is extracted with the writeTo(stream) method.
*
* @author Rickard ?berg
* @author Brat Baker (Atlassian)
* @author Alexey
* @version $Date: 2008-01-19 10:09:56 +0800 (Sat, 19 Jan 2008) $ $Id: FastByteArrayOutputStream.java 3000 2008-01-19 02:09:56Z tm_jee $
*/

public class FastByteArrayOutputStream extends OutputStream {

   // Static --------------------------------------------------------
   private static final int DEFAULT_BLOCK_SIZE = 8192;
   private LinkedList buffers;
   // Attributes ----------------------------------------------------
   // internal buffer
   private byte[] buffer;
   // is the stream closed?
   private boolean closed;
   private int blockSize;
   private int index;
   private int size;
   // Constructors --------------------------------------------------
   public FastByteArrayOutputStream() {
       this(DEFAULT_BLOCK_SIZE);
   }
   public FastByteArrayOutputStream(int aSize) {
       blockSize = aSize;
       buffer = new byte[blockSize];
   }
   public int getSize() {
       return size + index;
   }
   public void close() {
       closed = true;
   }
   public byte[] toByteArray() {
       byte[] data = new byte[getSize()];
       // Check if we have a list of buffers
       int pos = 0;
       if (buffers != null) {
           Iterator iter = buffers.iterator();
           while (iter.hasNext()) {
               byte[] bytes = (byte[]) iter.next();
               System.arraycopy(bytes, 0, data, pos, blockSize);
               pos += blockSize;
           }
       }
       // write the internal buffer directly
       System.arraycopy(buffer, 0, data, pos, index);
       return data;
   }
   public String toString() {
       return new String(toByteArray());
   }
   // OutputStream overrides ----------------------------------------
   public void write(int datum) throws IOException {
       if (closed) {
           throw new IOException("Stream closed");
       } else {
           if (index == blockSize) {
               addBuffer();
           }
           // store the byte
           buffer[index++] = (byte) datum;
       }
   }
   public void write(byte[] data, int offset, int length) throws IOException {
       if (data == null) {
           throw new NullPointerException();
       } else if ((offset < 0) || ((offset + length) > data.length) || (length < 0)) {
           throw new IndexOutOfBoundsException();
       } else if (closed) {
           throw new IOException("Stream closed");
       } else {
           if ((index + length) > blockSize) {
               int copyLength;
               do {
                   if (index == blockSize) {
                       addBuffer();
                   }
                   copyLength = blockSize - index;
                   if (length < copyLength) {
                       copyLength = length;
                   }
                   System.arraycopy(data, offset, buffer, index, copyLength);
                   offset += copyLength;
                   index += copyLength;
                   length -= copyLength;
               } while (length > 0);
           } else {
               // Copy in the subarray
               System.arraycopy(data, offset, buffer, index, length);
               index += length;
           }
       }
   }
   // Public
   public void writeTo(OutputStream out) throws IOException {
       // Check if we have a list of buffers
       if (buffers != null) {
           Iterator iter = buffers.iterator();
           while (iter.hasNext()) {
               byte[] bytes = (byte[]) iter.next();
               out.write(bytes, 0, blockSize);
           }
       }
       // write the internal buffer directly
       out.write(buffer, 0, index);
   }
   public void writeTo(RandomAccessFile out) throws IOException {
       // Check if we have a list of buffers
       if (buffers != null) {
           Iterator iter = buffers.iterator();
           while (iter.hasNext()) {
               byte[] bytes = (byte[]) iter.next();
               out.write(bytes, 0, blockSize);
           }
       }
       // write the internal buffer directly
       out.write(buffer, 0, index);
   }
   public void writeTo(Writer out, String encoding) throws IOException {
       /*
         There is design tradeoff between being fast, correct and using too much memory when decoding bytes to strings.
        The rules are thus :
        1. if there is only one buffer then its a simple String conversion
             REASON : Fast!!!
        2. uses full buffer allocation annd System.arrayCopy() to smooosh together the bytes
             and then use String conversion
             REASON : Fast at the expense of a known amount of memory (eg the used memory * 2)
       */
       if (buffers != null)
       {
           // RULE 2 : a balance between using some memory and speed
           writeToViaSmoosh(out, encoding);
       }
       else
       {
           // RULE 1 : fastest!
           writeToViaString(out, encoding);
       }
   }
   /**
    * This can ONLY be called if there is only a single buffer to write, instead
    * use {@link #writeTo(java.io.Writer, String)}, which auto detects if
    * {@link #writeToViaString(java.io.Writer, String)} is to be used or
    * {@link #writeToViaSmoosh(java.io.Writer, String)}.
    *
    * @param out      the JspWriter
    * @param encoding the encoding
    * @throws IOException
    */
   void writeToViaString(Writer out, String encoding) throws IOException
   {
       byte[] bufferToWrite = buffer; // this is always the last buffer to write
       int bufferToWriteLen = index;  // index points to our place in the last buffer
       writeToImpl(out, encoding, bufferToWrite, bufferToWriteLen);
   }
   /**
    * This is recommended to be used where there"s more than 1 buffer to write, instead
    * use {@link #writeTo(java.io.Writer, String)} which auto detects if
    * {@link #writeToViaString(java.io.Writer, String)} is to be used or
    * {@link #writeToViaSmoosh(java.io.Writer, String)}.
    * 
    * @param out
    * @param encoding
    * @throws IOException
    */
   void writeToViaSmoosh(Writer out, String encoding) throws IOException
   {
       byte[] bufferToWrite = toByteArray();
       int bufferToWriteLen = bufferToWrite.length;
       writeToImpl(out, encoding, bufferToWrite, bufferToWriteLen);
   }
   /**
    * Write bufferToWriteLen of bytes from bufferToWrite to
    * out encoding it at the same time.
    * 
    * @param out
    * @param encoding
    * @param bufferToWrite
    * @param bufferToWriteLen
    * @throws IOException
    */
   private void writeToImpl(Writer out, String encoding, byte[] bufferToWrite, int bufferToWriteLen)
           throws IOException
   {
       String writeStr;
       if (encoding != null)
       {
           writeStr = new String(bufferToWrite, 0, bufferToWriteLen, encoding);
       }
       else
       {
           writeStr = new String(bufferToWrite, 0, bufferToWriteLen);
       }
       out.write(writeStr);
   }
   /**
    * Create a new buffer and store the
    * current one in linked list
    */
   protected void addBuffer() {
       if (buffers == null) {
           buffers = new LinkedList();
       }
       buffers.addLast(buffer);
       buffer = new byte[blockSize];
       size += index;
       index = 0;
   }

} ////////////////////////////

import java.io.IOException; import javax.servlet.jsp.JspWriter; /**

* A test class for {@link webwork.util.FastByteArrayOutputStream}
*
* @author Brad Baker (Atlassian)
* @since $Date$ $Id$
*/

public class FastByteArrayOutputStreamTestCase extends AbstractEncodingTestCase {

   public void testLatinCharsets() throws Exception
   {
       assertEncoding(ASCII_TEXT, LATIN);
       assertEncoding(ASCII_TEXT, ASCII);
   }
   public void testRussianCharsets() throws Exception
   {
       assertEncoding(RUSSIAN_DESC_SHORT, KOI8_R);
       assertEncoding(RUSSIAN_DESC1, KOI8_R);
       assertEncoding(RUSSIAN_DESC_SHORT, WINDOWS_CYRILLIC);
       assertEncoding(RUSSIAN_DESC1, WINDOWS_CYRILLIC);
   }
   public void testUnicodeCharsets() throws Exception
   {
       String[] testStrs = {ASCII_TEXT_SHORT, ASCII_TEXT, RUSSIAN_DESC_SHORT, RUSSIAN_DESC1, CHINESE_TIMETRACKING, HUNGRIAN_APPLET_PROBLEM, };
       String[] encodings = { UTF_8, UTF_16, UBIG_ENDIAN, ULITTLE_ENDIAN, UBIG_ENDIAN_UNMARKED, ULITTLE_ENDIAN_UNMARKED };
       assertEncodings(testStrs, encodings);
   }
   protected void implementEncodingTest(final String srcStr, final String encoding, final int bufferSize)
           throws Exception
   {
       FastByteArrayOutputStream bout = new FastByteArrayOutputStream(bufferSize);
       byte[] bytes = srcStr.getBytes(encoding);
       bout.write(bytes);
       JspWriter writer = new StringCapturingJspWriter();
       bout.writeTo(writer, encoding);
       String actualStr = writer.toString();
       String expectedStr = new String(bytes, encoding);
       assertTheyAreEqual(expectedStr, actualStr, encoding);
   }
   /**
    * Before it was changed to use {@link java.nio.charset.CharsetDecoder} is took an this time
    * <p/>
    * Total Call Time = 1112.0ms
    * Average Call Time = 0.001112ms
    * <p/>
    * Now with the change it takes this time
    * <p/>
    * <p/>
    * The idea is that it did not get significantly worse in performance
    *
    * @throws IOException
    */
   public void testPerformanceOfWriteToJspWriter() throws IOException
   {
       final String NINEK_STR = makeRoughly(ASCII, 9 * K);
       final String FIFTYK_STR = makeRoughly(ASCII, 50 * K);
       final String ONEHUNDREDK_STR = makeRoughly(ASCII, 100 * K);
       testPerformanceOfWriteToJspWriter(new TextSource()
       {
           public String getDesc()
           {
               return "With < than 8K of data";
           }
           public String getText(final int times)
           {
               return ASCII_TEXT;
           }
       });
       testPerformanceOfWriteToJspWriter(new TextSource()
       {
           public String getDesc()
           {
               return "With > than 8K of data";
           }
           public String getText(final int times)
           {
               return NINEK_STR;
           }
       });
       testPerformanceOfWriteToJspWriter(new TextSource()
       {
           public String getDesc()
           {
               return "With a 2/3 mix of small data and 1/3 > 8K of data";
           }
           public String getText(final int times)
           {
               if (times % 3 == 0)
               {
                   return NINEK_STR;
               }
               return ASCII_TEXT;
           }
       });
       testPerformanceOfWriteToJspWriter(new TextSource()
       {
           public String getDesc()
           {
               return "With a 1/2 mix of small data and 1/2 > 8K of data";
           }
           public String getText(final int times)
           {
               if (times % 2 == 0)
               {
                   return NINEK_STR;
               }
               return ASCII_TEXT;
           }
       });
       testPerformanceOfWriteToJspWriter(new TextSource()
       {
           public String getDesc()
           {
               return "With 50K of data";
           }
           public String getText(final int times)
           {
               return FIFTYK_STR;
           }
       });
       testPerformanceOfWriteToJspWriter(new TextSource()
       {
           public String getDesc()
           {
               return "With 100K of data";
           }
           public String getText(final int times)
           {
               return ONEHUNDREDK_STR;
           }
       });
   }
   
   public void testPerformanceOfWriteToJspWriter(TextSource textSource) throws IOException
   {
       NoopJspWriter noopJspWriter = new NoopJspWriter();
       String[] methods = {
               "writeTo (using hueristics)",
               "writeToViaSmoosh",
       };
       System.out.println(textSource.getDesc());
       System.out.println();
       float bestTime = Float.MAX_VALUE;
       String bestMethod = methods[0];
       for (int methodIndex = 0; methodIndex < methods.length; methodIndex++)
       {
           String method = methods[methodIndex];
           float totalTime = 0;
           final int MAX_TIMES = 10;
           final int MAX_ITERATIONS = 100;
           for (int times = 0; times < MAX_TIMES; times++)
           {
               String srcText = textSource.getText(times);
               for (int i = 0; i < MAX_ITERATIONS; i++)
               {
                   FastByteArrayOutputStream bout = new FastByteArrayOutputStream();
                   bout.write(srcText.getBytes(UTF_8));
                   // just time the JspWriter output. And let it warm u first as well
                   if (times > 3)
                   {
                       long then = System.currentTimeMillis();
                       switch (methodIndex)
                       {
                           case 0:
                               bout.writeTo(noopJspWriter, UTF_8);
                               break;
                           case 1:
                               bout.writeToViaSmoosh(noopJspWriter, UTF_8);
                               break;
                       }
                       long now = System.currentTimeMillis();
                       totalTime += (now - then);
                   }
               }
           }
           float avgTime = totalTime / MAX_TIMES / MAX_ITERATIONS;
           System.out.println(method + "  - Total Call Time = " + totalTime + "ms");
           System.out.println(method + " - Average Call Time = " + avgTime + "ms");
           System.out.println();
           if (avgTime < bestTime) {
               bestTime = avgTime;
               bestMethod = method;
           }
       }
       System.out.println(bestMethod + " was the best method - Average Call Time = " + bestTime + "ms");
       System.out.println("____________________\n");
   }
   interface TextSource
   {
       String getDesc();
       String getText(int times);
   }
   static class StringCapturingJspWriter extends NoopJspWriter
   {
       StringCapturingJspWriter()
       {
           super(true);
       }
   }
   static class NoopJspWriter extends JspWriter
   {
       final StringBuffer sb = new StringBuffer();
       final boolean capture;
       NoopJspWriter()
       {
           this(false);
       }
       NoopJspWriter(boolean capture)
       {
           super(0, false);
           this.capture = capture;
       }
       NoopJspWriter(final int i, final boolean b)
       {
           super(i, b);
           this.capture = false;
       }
       public String toString()
       {
           return sb.toString();
       }
       public void clear() throws IOException
       {
       }
       public void clearBuffer() throws IOException
       {
       }
       public void close() throws IOException
       {
       }
       public void flush() throws IOException
       {
       }
       public int getRemaining()
       {
           return 0;
       }
       public void newLine() throws IOException
       {
       }
       public void print(final char c) throws IOException
       {
           if (capture)
           {
               sb.append(c);
           }
       }
       public void print(final double v) throws IOException
       {
           if (capture)
           {
               sb.append(v);
           }
       }
       public void print(final float v) throws IOException
       {
           if (capture)
           {
               sb.append(v);
           }
       }
       public void print(final int i) throws IOException
       {
           if (capture)
           {
               sb.append(i);
           }
       }
       public void print(final long l) throws IOException
       {
           if (capture)
           {
               sb.append(l);
           }
       }
       public void print(final Object o) throws IOException
       {
           if (capture)
           {
               sb.append(o);
           }
       }
       public void print(final String s) throws IOException
       {
           if (capture)
           {
               sb.append(s);
           }
       }
       public void print(final boolean b) throws IOException
       {
           if (capture)
           {
               sb.append(b);
           }
       }
       public void print(final char[] chars) throws IOException
       {
           if (capture)
           {
               sb.append(chars);
           }
       }
       public void println() throws IOException
       {
           print("\n");
       }
       public void println(final char c) throws IOException
       {
           print(c);
           println();
       }
       public void println(final double v) throws IOException
       {
           print(v);
           println();
       }
       public void println(final float v) throws IOException
       {
           print(v);
           println();
       }
       public void println(final int i) throws IOException
       {
           print(i);
           println();
       }
       public void println(final long l) throws IOException
       {
           print(l);
           println();
       }
       public void println(final Object o) throws IOException
       {
           print(o);
           println();
       }
       public void println(final String s) throws IOException
       {
           print(s);
           println();
       }
       public void println(final boolean b) throws IOException
       {
           print(b);
           println();
       }
       public void println(final char[] chars) throws IOException
       {
           print(chars);
           println();
       }
       public void write(final char cbuf[], final int off, final int len) throws IOException
       {
           String s = new String(cbuf, off, len);
           print(s);
       }
   }

}



 </source>
   
  
 
  



Provides true Closable semantics ordinarily missing in a java.io.ByteArrayOutputStream

   <source lang="java">


/* Copyright (c) 2001-2009, The HSQL Development Group

* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the HSQL Development Group nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; /* $Id: ClosableByteArrayOutputStream.java 2946 2009-03-22 17:44:48Z fredt $ */ /**

* @todo - finer-grained synchronization to reduce average
* potential monitor contention
*/

/**

* Provides true Closable semantics ordinarily missing in a
* {@link java.io.ByteArrayOutputStream}. <p>
*
* Accumulates output in a byte array that automatically grows as needed.<p>
*
* Data is retrieved using toByteArray(),
* toByteArrayInputStream(), toString() and
* toString(encoding). <p>
*
* {@link #close() Closing} a ClosableByteArrayOutputStream prevents
* further write operations, but all other operations may succeed until after
* the first invocation of {@link #free() free()}.<p>
*
* Freeing a ClosableByteArrayOutputStream closes the stream and
* releases the internal buffer, preventing successful invocation of all
* operations, with the exception of size()<tt>, <tt>close(),
* isClosed(), free() and isFreed(). <p>
*
* This class is especially useful when an accumulating output stream must be
* handed off to an extenal client under contract that the stream should
* exhibit true Closable behaviour in response both to internally tracked
* events and to client invocation of the OutputStream.close() method.
*
* @author boucherb@users
* @version 1.9.0
* @since 1.9.0
*/

public class ClosableByteArrayOutputStream extends OutputStream {

   /**
    * Data buffer.
    */
   protected byte[] buf;
   /**
    * # of valid bytes in buffer.
    */
   protected int count;
   /**
    * Whether this stream is closed.
    */
   protected boolean closed;
   /**
    * Whether this stream is freed.
    */
   protected boolean freed;
   /**
    * Creates a new output stream. <p>
    *
    * The buffer capacity is initially 32 bytes, though its size increases
    * if necessary.
    */
   public ClosableByteArrayOutputStream() {
       this(32);
   }
   /**
    * Creates a new output stream with a buffer capacity of the specified
    * size, in bytes.
    *
    * @param size the initial size.
    * @exception IllegalArgumentException if size is negative.
    */
   public ClosableByteArrayOutputStream(int size)
   throws IllegalArgumentException {
       if (size < 0) {
           throw new IllegalArgumentException("Negative initial size: "
                                              + size);    // NOI18N
       }
       buf = new byte[size];
   }
   /**
    * Writes the specified single byte.
    *
    * @param b the single byte to be written.
    * @throws java.io.IOException if an I/O error occurs.
    *      In particular, an IOException may be thrown
    *      if this output stream has been {@link #close() closed}.
    */
   public synchronized void write(int b) throws IOException {
       checkClosed();
       int newcount = count + 1;
       if (newcount > buf.length) {
           buf = copyOf(buf, Math.max(buf.length << 1, newcount));
       }
       buf[count] = (byte) b;
       count      = newcount;
   }
   /**
    * Writes the specified portion of the designated octet sequence. <p>
    *
    * @param b the data.
    * @param off the start offset in the data.
    * @param len the number of bytes to write.
    * @throws java.io.IOException if an I/O error occurs.
    *      In particular, an IOException may be thrown
    *      if this output stream has been {@link #close() closed}.
    */
   public synchronized void write(byte b[], int off,
                                  int len) throws IOException {
       checkClosed();
       if ((off < 0) || (off > b.length) || (len < 0)
               || ((off + len) > b.length) || ((off + len) < 0)) {
           throw new IndexOutOfBoundsException();
       } else if (len == 0) {
           return;
       }
       int newcount = count + len;
       if (newcount > buf.length) {
           buf = copyOf(buf, Math.max(buf.length << 1, newcount));
       }
       System.arraycopy(b, off, buf, count, len);
       count = newcount;
   }
   /**
    * By default, does nothing. <p>
    *
    * @throws java.io.IOException if an I/O error occurs.
    *      In particular, an IOException may be thrown
    *      if this output stream has been {@link #close() closed}.
    */
   public void flush() throws IOException {
       checkClosed();
   }
   /**
    * Writes the complete contents of this stream"s accumulated data to the
    * specified output stream. <p>
    *
    * The operation occurs as if by calling out.write(buf, 0, count).
    *
    * @param out the output stream to which to write the data.
    * @throws java.io.IOException if an I/O error occurs.
    *      In particular, an IOException may be thrown
    *      if this output stream has been {@link #free() freed}.
    */
   public synchronized void writeTo(OutputStream out) throws IOException {
       checkFreed();
       out.write(buf, 0, count);
   }
   /**
    * Returns the current capacity of this stream"s data buffer.
    *
    * @return  the length of the internal data array
    * @throws java.io.IOException if an I/O error occurs.
    *      In particular, an IOException may be thrown
    *      if this output stream has been {@link #free() freed}.
    */
   public synchronized int capacity() throws IOException {
       checkFreed();
       return buf.length;
   }
   /**
    * Resets the count field of this output stream to zero, so that
    * all currently accumulated data is effectively discarded. <p>
    *
    * Further write operations will reuse the allocated buffer space. <p>
    *
    * @see #count
    * @throws java.io.IOException if an I/O error occurs.
    *      In particular, an IOException may be thrown
    *      if this output stream has been {@link #close() closed}.
    */
   public synchronized void reset() throws IOException {
       checkClosed();
       count = 0;
   }
   /**
    * Attempts to reduce this stream"s capacity to its current size. <p>
    *
    * If the data buffer is larger than necessary to hold its current sequence
    * of bytes, then it may be resized to become more space efficient.
    * Calling this method may, but is not required to, affect the value
    * returned by a subsequent call to the {@link #capacity()} method. <p>
    *
    * @throws java.io.IOException if an I/O error occurs.
    *      In particular, an IOException may be thrown
    *      if this output stream has been {@link #free() freed}.
    */
   public synchronized void trimToSize() throws IOException {
       checkFreed();
       if (buf.length > count) {
           buf = copyOf(buf, count);
       }
   }
   /**
    * Retrieves a copy of this stream"s accumated data, as a byte array.
    *
    * @return a copy of this stream"s accumated data, as a byte array.
    * @see #size()
    * @throws java.io.IOException if an I/O error occurs.
    *      In particular, an IOException may be thrown
    *      if this output stream has been {@link #free() freed}.
    */
   public synchronized byte[] toByteArray() throws IOException {
       checkFreed();
       return copyOf(buf, count);
   }
   /**
    * Returns the current size of this stream"s accumated data.
    *
    * @return the value of the count field, which is the number
    *      of valid bytes in this output stream.
    * @see #count
    * @throws java.io.IOException never
    */
   public synchronized int size() throws IOException {
       return count;
   }
   /**
    * Sets the size of this stream"s accumulated data. <p>
    *
    * @param   newSize the new size
    * @throws  ArrayIndexOutOfBoundsException if new size is negative
    */
   public synchronized void setSize(int newSize) {
       if (newSize < 0) {
           throw new ArrayIndexOutOfBoundsException(newSize);
       } else if (newSize > buf.length) {
           buf = copyOf(buf, Math.max(buf.length << 1, newSize));
       }
       count = newSize;
   }
   /**
    * Performs an effecient (zero-copy) conversion of the data accumulated in
    * this output stream to an input stream. <p>
    *
    * To ensure the future integrity of the resulting input stream, {@link
    * #free() free} is invoked upon this output stream as a side-effect.
    *
    * @return an input stream representing this output stream"s accumulated
    *      data
    * @throws java.io.IOException if an I/O error occurs.
    *      In particular, an IOException may be thrown
    *      if this output stream has been {@link #free() freed}.
    */
   public synchronized ByteArrayInputStream toByteArrayInputStream()
   throws IOException {
       checkFreed();
       ByteArrayInputStream inputStream = new ByteArrayInputStream(buf, 0,
           count);
       free();
       return inputStream;
   }
   /**
    * Converts this stream"s accumuated data into a string, translating bytes
    * into characters according to the platform"s default character encoding.
    *
    * @return String translated from this stream"s accumuated data.
    * @throws RuntimeException may be thrown if this output stream has been
    *      {@link #free() freed}.
    */
   public synchronized String toString() {
       try {
           checkFreed();
       } catch (IOException ex) {
           throw new RuntimeException(ex.toString());
       }
       return new String(buf, 0, count);
   }
   /**
    * Converts this stream"s accumuated data into a string, translating bytes
    * into characters according to the specified character encoding.
    *
    * @return String translated from the buffer"s contents.
    * @param enc a character-encoding name.
    * @throws java.io.IOException may be thrown if this output stream has been
    *      {@link #free() freed}.
    * @throws UnsupportedEncodingException If the named encoding is not
    *      supported.
    */
   public synchronized String toString(String enc)
   throws IOException, UnsupportedEncodingException {
       checkFreed();
       return new String(buf, 0, count, enc);
   }
   /**
    * Closes this object for further writing. <p>
    *
    * Other operations may continue to succeed until after the first invocation
    * of {@link #free() free()}. <p>
    *
    * @throws java.io.IOException if an I/O error occurs (default: never)
    */
   public synchronized void close() throws IOException {
       closed = true;
   }
   /**
    * Retrieves whether this stream is closed. <p>
    * @return true if this stream is closed, else false
    */
   public synchronized boolean isClosed() {
       return closed;
   }
   /**
    * Closes this object and releases the underlying buffer for
    * garbage collection. <p>
    *
    * @throws java.io.IOException if an I/O error occurs while closing
    *      this stream (default: never).
    */
   public synchronized void free() throws IOException {
       closed = true;
       freed  = true;
       buf    = null;
       count  = 0;
   }
   /**
    * Retrieves whether this stream is freed. <p>
    *
    * @return true if this stream is freed; else false.
    */
   public synchronized boolean isFreed() {
       return freed;
   }
   /**
    * Tests whether this stream is closed. <p>
    *
    * @throws java.io.IOException if this stream is closed.
    */
   protected synchronized void checkClosed() throws IOException {
       if (closed) {
           throw new IOException("stream is closed.");    // NOI18N
       }
   }
   /**
    * Tests whether this stream is freed. <p>
    *
    * @throws java.io.IOException if this stream is freed.
    */
   protected synchronized void checkFreed() throws IOException {
       if (freed) {
           throw new IOException("stream buffer is freed.");    // NOI18N
       }
   }
   /**
    * Retrieves a copy of original with the given
    * newLength. <p>
    *
    * @param original the object to copy
    * @param newLength the length of the copy
    * @return copy of original with the given newLength
    */
   protected byte[] copyOf(byte[] original, int newLength) {
       byte[] copy = new byte[newLength];
       System.arraycopy(original, 0, copy, 0,
                        Math.min(original.length, newLength));
       return copy;
   }

}

 </source>
   
  
 
  



Use ByteArrayOutputStream

   <source lang="java">
  

import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; public class ByteArrayIOApp {

 public static void main(String args[]) throws IOException {
   ByteArrayOutputStream outStream = new ByteArrayOutputStream();
   String s = "This is a test.";
   for (int i = 0; i < s.length(); ++i)
     outStream.write(s.charAt(i));
   System.out.println("outstream: " + outStream);
   System.out.println("size: " + outStream.size());
   ByteArrayInputStream inStream;
   inStream = new ByteArrayInputStream(outStream.toByteArray());
   int inBytes = inStream.available();
   System.out.println("inStream has " + inBytes + " available bytes");
   byte inBuf[] = new byte[inBytes];
   int bytesRead = inStream.read(inBuf, 0, inBytes);
   System.out.println(bytesRead + " bytes were read");
   System.out.println("They are: " + new String(inBuf));
 }

}


 </source>