001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.io.output; 018 019import java.io.BufferedInputStream; 020import java.io.IOException; 021import java.io.InputStream; 022import java.io.OutputStream; 023 024import org.apache.commons.io.build.AbstractOrigin; 025import org.apache.commons.io.build.AbstractStreamBuilder; 026import org.apache.commons.io.function.Uncheck; 027import org.apache.commons.io.input.UnsynchronizedByteArrayInputStream; 028 029/** 030 * Implements a version of {@link AbstractByteArrayOutputStream} <strong>without</strong> any concurrent thread safety. 031 * <p> 032 * To build an instance, use {@link Builder}. 033 * </p> 034 * 035 * @see Builder 036 * @since 2.7 037 */ 038//@NotThreadSafe 039public final class UnsynchronizedByteArrayOutputStream extends AbstractByteArrayOutputStream { 040 041 // @formatter:off 042 /** 043 * Builds a new {@link UnsynchronizedByteArrayOutputStream}. 044 * 045 * <p> 046 * Using File IO: 047 * </p> 048 * <pre>{@code 049 * UnsynchronizedByteArrayOutputStream s = UnsynchronizedByteArrayOutputStream.builder() 050 * .setBufferSize(8192) 051 * .get();} 052 * </pre> 053 * <p> 054 * Using NIO Path: 055 * </p> 056 * <pre>{@code 057 * UnsynchronizedByteArrayOutputStream s = UnsynchronizedByteArrayOutputStream.builder() 058 * .setBufferSize(8192) 059 * .get();} 060 * </pre> 061 * 062 * @see #get() 063 */ 064 // @formatter:on 065 public static class Builder extends AbstractStreamBuilder<UnsynchronizedByteArrayOutputStream, Builder> { 066 067 /** 068 * Builds a new {@link UnsynchronizedByteArrayOutputStream}. 069 * 070 * <p> 071 * This builder use the following aspects: 072 * </p> 073 * <ul> 074 * <li>{@link #getBufferSize()}</li> 075 * </ul> 076 * 077 * @return a new instance. 078 * @see AbstractOrigin#getByteArray() 079 */ 080 @Override 081 public UnsynchronizedByteArrayOutputStream get() { 082 return new UnsynchronizedByteArrayOutputStream(getBufferSize()); 083 } 084 085 } 086 087 /** 088 * Constructs a new {@link Builder}. 089 * 090 * @return a new {@link Builder}. 091 */ 092 public static Builder builder() { 093 return new Builder(); 094 } 095 096 /** 097 * Fetches entire contents of an {@link InputStream} and represent same data as result InputStream. 098 * <p> 099 * This method is useful where, 100 * </p> 101 * <ul> 102 * <li>Source InputStream is slow.</li> 103 * <li>It has network resources associated, so we cannot keep it open for long time.</li> 104 * <li>It has network timeout associated.</li> 105 * </ul> 106 * It can be used in favor of {@link #toByteArray()}, since it avoids unnecessary allocation and copy of byte[].<br> 107 * This method buffers the input internally, so there is no need to use a {@link BufferedInputStream}. 108 * 109 * @param input Stream to be fully buffered. 110 * @return A fully buffered stream. 111 * @throws IOException if an I/O error occurs. 112 */ 113 public static InputStream toBufferedInputStream(final InputStream input) throws IOException { 114 return toBufferedInputStream(input, DEFAULT_SIZE); 115 } 116 117 /** 118 * Fetches entire contents of an {@link InputStream} and represent same data as result InputStream. 119 * <p> 120 * This method is useful where, 121 * </p> 122 * <ul> 123 * <li>Source InputStream is slow.</li> 124 * <li>It has network resources associated, so we cannot keep it open for long time.</li> 125 * <li>It has network timeout associated.</li> 126 * </ul> 127 * It can be used in favor of {@link #toByteArray()}, since it avoids unnecessary allocation and copy of byte[].<br> 128 * This method buffers the input internally, so there is no need to use a {@link BufferedInputStream}. 129 * 130 * @param input Stream to be fully buffered. 131 * @param size the initial buffer size 132 * @return A fully buffered stream. 133 * @throws IOException if an I/O error occurs. 134 */ 135 public static InputStream toBufferedInputStream(final InputStream input, final int size) throws IOException { 136 // It does not matter if a ByteArrayOutputStream is not closed as close() is a no-op 137 try (UnsynchronizedByteArrayOutputStream output = builder().setBufferSize(size).get()) { 138 output.write(input); 139 return output.toInputStream(); 140 } 141 } 142 143 /** 144 * Constructs a new byte array output stream. The buffer capacity is initially 145 * 146 * {@value AbstractByteArrayOutputStream#DEFAULT_SIZE} bytes, though its size increases if necessary. 147 * @deprecated Use {@link #builder()}, {@link Builder}, and {@link Builder#get()}. 148 */ 149 @Deprecated 150 public UnsynchronizedByteArrayOutputStream() { 151 this(DEFAULT_SIZE); 152 } 153 154 /** 155 * Constructs a new byte array output stream, with a buffer capacity of the specified size, in bytes. 156 * 157 * @param size the initial size 158 * @throws IllegalArgumentException if size is negative 159 * @deprecated Use {@link #builder()}, {@link Builder}, and {@link Builder#get()}. Will be private in 3.0.0. 160 */ 161 @Deprecated 162 public UnsynchronizedByteArrayOutputStream(final int size) { 163 if (size < 0) { 164 throw new IllegalArgumentException("Negative initial size: " + size); 165 } 166 needNewBuffer(size); 167 } 168 169 /** 170 * @see java.io.ByteArrayOutputStream#reset() 171 */ 172 @Override 173 public void reset() { 174 resetImpl(); 175 } 176 177 @Override 178 public int size() { 179 return count; 180 } 181 182 @Override 183 public byte[] toByteArray() { 184 return toByteArrayImpl(); 185 } 186 187 @Override 188 public InputStream toInputStream() { 189 // @formatter:off 190 return toInputStream((buffer, offset, length) -> Uncheck 191 .get(() -> UnsynchronizedByteArrayInputStream.builder() 192 .setByteArray(buffer) 193 .setOffset(offset) 194 .setLength(length) 195 .get())); 196 // @formatter:on 197 } 198 199 @Override 200 public void write(final byte[] b, final int off, final int len) { 201 if (off < 0 || off > b.length || len < 0 || off + len > b.length || off + len < 0) { 202 throw new IndexOutOfBoundsException(String.format("offset=%,d, length=%,d", off, len)); 203 } 204 if (len == 0) { 205 return; 206 } 207 writeImpl(b, off, len); 208 } 209 210 @Override 211 public int write(final InputStream in) throws IOException { 212 return writeImpl(in); 213 } 214 215 @Override 216 public void write(final int b) { 217 writeImpl(b); 218 } 219 220 @Override 221 public void writeTo(final OutputStream out) throws IOException { 222 writeToImpl(out); 223 } 224}