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