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