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 * https://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.IOUtils; 025import org.apache.commons.io.build.AbstractOrigin; 026import org.apache.commons.io.build.AbstractStreamBuilder; 027import org.apache.commons.io.function.Uncheck; 028import org.apache.commons.io.input.UnsynchronizedByteArrayInputStream; 029 030/** 031 * Implements a version of {@link AbstractByteArrayOutputStream} <strong>without</strong> any concurrent thread safety. 032 * <p> 033 * To build an instance, use {@link Builder}. 034 * </p> 035 * 036 * @see Builder 037 * @since 2.7 038 */ 039//@NotThreadSafe 040public final class UnsynchronizedByteArrayOutputStream extends AbstractByteArrayOutputStream<UnsynchronizedByteArrayOutputStream> { 041 042 // @formatter:off 043 /** 044 * Builds a new {@link UnsynchronizedByteArrayOutputStream}. 045 * 046 * <p> 047 * Using File IO: 048 * </p> 049 * <pre>{@code 050 * UnsynchronizedByteArrayOutputStream s = UnsynchronizedByteArrayOutputStream.builder() 051 * .setBufferSize(8192) 052 * .get();} 053 * </pre> 054 * <p> 055 * Using NIO Path: 056 * </p> 057 * <pre>{@code 058 * UnsynchronizedByteArrayOutputStream s = UnsynchronizedByteArrayOutputStream.builder() 059 * .setBufferSize(8192) 060 * .get();} 061 * </pre> 062 * 063 * @see #get() 064 */ 065 // @formatter:on 066 public static class Builder extends AbstractStreamBuilder<UnsynchronizedByteArrayOutputStream, Builder> { 067 068 /** 069 * Constructs a new builder of {@link UnsynchronizedByteArrayOutputStream}. 070 */ 071 public Builder() { 072 // empty 073 } 074 075 /** 076 * Builds a new {@link UnsynchronizedByteArrayOutputStream}. 077 * 078 * <p> 079 * This builder uses the following aspects: 080 * </p> 081 * <ul> 082 * <li>{@link #getBufferSize()}</li> 083 * </ul> 084 * 085 * @return a new instance. 086 * @see AbstractOrigin#getByteArray() 087 * @see #getUnchecked() 088 */ 089 @Override 090 public UnsynchronizedByteArrayOutputStream get() { 091 return new UnsynchronizedByteArrayOutputStream(this); 092 } 093 094 } 095 096 /** 097 * Constructs a new {@link Builder}. 098 * 099 * @return a new {@link Builder}. 100 */ 101 public static Builder builder() { 102 return new Builder(); 103 } 104 105 /** 106 * Fetches entire contents of an {@link InputStream} and represent same data as result InputStream. 107 * <p> 108 * This method is useful where, 109 * </p> 110 * <ul> 111 * <li>Source InputStream is slow.</li> 112 * <li>It has network resources associated, so we cannot keep it open for long time.</li> 113 * <li>It has network timeout associated.</li> 114 * </ul> 115 * <p> 116 * It can be used in favor of {@link #toByteArray()}, since it avoids unnecessary allocation and copy of byte[].<br> 117 * This method buffers the input internally, so there is no need to use a {@link BufferedInputStream}. 118 * </p> 119 * 120 * @param input Stream to be fully buffered. 121 * @return A fully buffered stream. 122 * @throws IOException if an I/O error occurs. 123 */ 124 public static InputStream toBufferedInputStream(final InputStream input) throws IOException { 125 return toBufferedInputStream(input, DEFAULT_SIZE); 126 } 127 128 /** 129 * Fetches entire contents of an {@link InputStream} and represent same data as result InputStream. 130 * <p> 131 * This method is useful where, 132 * </p> 133 * <ul> 134 * <li>Source InputStream is slow.</li> 135 * <li>It has network resources associated, so we cannot keep it open for long time.</li> 136 * <li>It has network timeout associated.</li> 137 * </ul> 138 * <p> 139 * It can be used in favor of {@link #toByteArray()}, since it avoids unnecessary allocation and copy of byte[].<br> 140 * This method buffers the input internally, so there is no need to use a {@link BufferedInputStream}. 141 * </p> 142 * 143 * @param input Stream to be fully buffered. 144 * @param size the initial buffer size. 145 * @return A fully buffered stream. 146 * @throws IOException if an I/O error occurs. 147 */ 148 public static InputStream toBufferedInputStream(final InputStream input, final int size) throws IOException { 149 // It does not matter if a ByteArrayOutputStream is not closed as close() is a no-op 150 try (UnsynchronizedByteArrayOutputStream output = builder().setBufferSize(size).get()) { 151 output.write(input); 152 return output.toInputStream(); 153 } 154 } 155 156 /** 157 * Constructs a new byte array output stream. The buffer capacity is initially. 158 * 159 * {@value AbstractByteArrayOutputStream#DEFAULT_SIZE} bytes, though its size increases if necessary. 160 * @deprecated Use {@link #builder()}, {@link Builder}, and {@link Builder#get()}. 161 */ 162 @Deprecated 163 public UnsynchronizedByteArrayOutputStream() { 164 this(DEFAULT_SIZE); 165 } 166 167 private UnsynchronizedByteArrayOutputStream(final Builder builder) { 168 this(builder.getBufferSize()); 169 } 170 171 /** 172 * Constructs a new byte array output stream, with a buffer capacity of the specified size, in bytes. 173 * 174 * @param size the initial size. 175 * @throws IllegalArgumentException if size is negative. 176 * @deprecated Use {@link #builder()}, {@link Builder}, and {@link Builder#get()}. Will be private in 3.0.0. 177 */ 178 @Deprecated 179 public UnsynchronizedByteArrayOutputStream(final int size) { 180 if (size < 0) { 181 throw new IllegalArgumentException("Negative initial size: " + size); 182 } 183 needNewBuffer(size); 184 } 185 186 /** 187 * @see java.io.ByteArrayOutputStream#reset() 188 */ 189 @Override 190 public void reset() { 191 resetImpl(); 192 } 193 194 @Override 195 public int size() { 196 return count; 197 } 198 199 @Override 200 public byte[] toByteArray() { 201 return toByteArrayImpl(); 202 } 203 204 @Override 205 public InputStream toInputStream() { 206 // @formatter:off 207 return toInputStream((buffer, offset, length) -> Uncheck 208 .get(() -> UnsynchronizedByteArrayInputStream.builder() 209 .setByteArray(buffer) 210 .setOffset(offset) 211 .setLength(length) 212 .get())); 213 // @formatter:on 214 } 215 216 @Override 217 public void write(final byte[] b, final int off, final int len) { 218 IOUtils.checkFromIndexSize(b, off, len); 219 if (len == 0) { 220 return; 221 } 222 writeImpl(b, off, len); 223 } 224 225 @Override 226 public int write(final InputStream in) throws IOException { 227 return writeImpl(in); 228 } 229 230 @Override 231 public void write(final int b) { 232 writeImpl(b); 233 } 234 235 @Override 236 public void writeTo(final OutputStream out) throws IOException { 237 writeToImpl(out); 238 } 239}