1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * https://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.commons.io.output; 18 19 import java.io.BufferedInputStream; 20 import java.io.IOException; 21 import java.io.InputStream; 22 import java.io.OutputStream; 23 24 import org.apache.commons.io.build.AbstractOrigin; 25 import org.apache.commons.io.build.AbstractStreamBuilder; 26 import org.apache.commons.io.function.Uncheck; 27 import org.apache.commons.io.input.UnsynchronizedByteArrayInputStream; 28 29 /** 30 * Implements a version of {@link AbstractByteArrayOutputStream} <strong>without</strong> any concurrent thread safety. 31 * <p> 32 * To build an instance, use {@link Builder}. 33 * </p> 34 * 35 * @see Builder 36 * @since 2.7 37 */ 38 //@NotThreadSafe 39 public final class UnsynchronizedByteArrayOutputStream extends AbstractByteArrayOutputStream<UnsynchronizedByteArrayOutputStream> { 40 41 // @formatter:off 42 /** 43 * Builds a new {@link UnsynchronizedByteArrayOutputStream}. 44 * 45 * <p> 46 * Using File IO: 47 * </p> 48 * <pre>{@code 49 * UnsynchronizedByteArrayOutputStream s = UnsynchronizedByteArrayOutputStream.builder() 50 * .setBufferSize(8192) 51 * .get();} 52 * </pre> 53 * <p> 54 * Using NIO Path: 55 * </p> 56 * <pre>{@code 57 * UnsynchronizedByteArrayOutputStream s = UnsynchronizedByteArrayOutputStream.builder() 58 * .setBufferSize(8192) 59 * .get();} 60 * </pre> 61 * 62 * @see #get() 63 */ 64 // @formatter:on 65 public static class Builder extends AbstractStreamBuilder<UnsynchronizedByteArrayOutputStream, Builder> { 66 67 /** 68 * Constructs a new builder of {@link UnsynchronizedByteArrayOutputStream}. 69 */ 70 public Builder() { 71 // empty 72 } 73 74 /** 75 * Builds a new {@link UnsynchronizedByteArrayOutputStream}. 76 * 77 * <p> 78 * This builder uses the following aspects: 79 * </p> 80 * <ul> 81 * <li>{@link #getBufferSize()}</li> 82 * </ul> 83 * 84 * @return a new instance. 85 * @see AbstractOrigin#getByteArray() 86 * @see #getUnchecked() 87 */ 88 @Override 89 public UnsynchronizedByteArrayOutputStream get() { 90 return new UnsynchronizedByteArrayOutputStream(this); 91 } 92 93 } 94 95 /** 96 * Constructs a new {@link Builder}. 97 * 98 * @return a new {@link Builder}. 99 */ 100 public static Builder builder() { 101 return new Builder(); 102 } 103 104 /** 105 * Fetches entire contents of an {@link InputStream} and represent same data as result InputStream. 106 * <p> 107 * This method is useful where, 108 * </p> 109 * <ul> 110 * <li>Source InputStream is slow.</li> 111 * <li>It has network resources associated, so we cannot keep it open for long time.</li> 112 * <li>It has network timeout associated.</li> 113 * </ul> 114 * It can be used in favor of {@link #toByteArray()}, since it avoids unnecessary allocation and copy of byte[].<br> 115 * This method buffers the input internally, so there is no need to use a {@link BufferedInputStream}. 116 * 117 * @param input Stream to be fully buffered. 118 * @return A fully buffered stream. 119 * @throws IOException if an I/O error occurs. 120 */ 121 public static InputStream toBufferedInputStream(final InputStream input) throws IOException { 122 return toBufferedInputStream(input, DEFAULT_SIZE); 123 } 124 125 /** 126 * Fetches entire contents of an {@link InputStream} and represent same data as result InputStream. 127 * <p> 128 * This method is useful where, 129 * </p> 130 * <ul> 131 * <li>Source InputStream is slow.</li> 132 * <li>It has network resources associated, so we cannot keep it open for long time.</li> 133 * <li>It has network timeout associated.</li> 134 * </ul> 135 * It can be used in favor of {@link #toByteArray()}, since it avoids unnecessary allocation and copy of byte[].<br> 136 * This method buffers the input internally, so there is no need to use a {@link BufferedInputStream}. 137 * 138 * @param input Stream to be fully buffered. 139 * @param size the initial buffer size 140 * @return A fully buffered stream. 141 * @throws IOException if an I/O error occurs. 142 */ 143 public static InputStream toBufferedInputStream(final InputStream input, final int size) throws IOException { 144 // It does not matter if a ByteArrayOutputStream is not closed as close() is a no-op 145 try (UnsynchronizedByteArrayOutputStream output = builder().setBufferSize(size).get()) { 146 output.write(input); 147 return output.toInputStream(); 148 } 149 } 150 151 /** 152 * Constructs a new byte array output stream. The buffer capacity is initially 153 * 154 * {@value AbstractByteArrayOutputStream#DEFAULT_SIZE} bytes, though its size increases if necessary. 155 * @deprecated Use {@link #builder()}, {@link Builder}, and {@link Builder#get()}. 156 */ 157 @Deprecated 158 public UnsynchronizedByteArrayOutputStream() { 159 this(DEFAULT_SIZE); 160 } 161 162 private UnsynchronizedByteArrayOutputStream(final Builder builder) { 163 this(builder.getBufferSize()); 164 } 165 166 /** 167 * Constructs a new byte array output stream, with a buffer capacity of the specified size, in bytes. 168 * 169 * @param size the initial size 170 * @throws IllegalArgumentException if size is negative 171 * @deprecated Use {@link #builder()}, {@link Builder}, and {@link Builder#get()}. Will be private in 3.0.0. 172 */ 173 @Deprecated 174 public UnsynchronizedByteArrayOutputStream(final int size) { 175 if (size < 0) { 176 throw new IllegalArgumentException("Negative initial size: " + size); 177 } 178 needNewBuffer(size); 179 } 180 181 /** 182 * @see java.io.ByteArrayOutputStream#reset() 183 */ 184 @Override 185 public void reset() { 186 resetImpl(); 187 } 188 189 @Override 190 public int size() { 191 return count; 192 } 193 194 @Override 195 public byte[] toByteArray() { 196 return toByteArrayImpl(); 197 } 198 199 @Override 200 public InputStream toInputStream() { 201 // @formatter:off 202 return toInputStream((buffer, offset, length) -> Uncheck 203 .get(() -> UnsynchronizedByteArrayInputStream.builder() 204 .setByteArray(buffer) 205 .setOffset(offset) 206 .setLength(length) 207 .get())); 208 // @formatter:on 209 } 210 211 @Override 212 public void write(final byte[] b, final int off, final int len) { 213 if (off < 0 || off > b.length || len < 0 || off + len > b.length || off + len < 0) { 214 throw new IndexOutOfBoundsException(String.format("offset=%,d, length=%,d", off, len)); 215 } 216 if (len == 0) { 217 return; 218 } 219 writeImpl(b, off, len); 220 } 221 222 @Override 223 public int write(final InputStream in) throws IOException { 224 return writeImpl(in); 225 } 226 227 @Override 228 public void write(final int b) { 229 writeImpl(b); 230 } 231 232 @Override 233 public void writeTo(final OutputStream out) throws IOException { 234 writeToImpl(out); 235 } 236 }