001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.commons.compress.utils; 020 021import java.io.ByteArrayOutputStream; 022import java.io.Closeable; 023import java.io.EOFException; 024import java.io.IOException; 025import java.io.InputStream; 026import java.io.OutputStream; 027import java.nio.ByteBuffer; 028import java.nio.channels.ReadableByteChannel; 029 030/** 031 * Utility functions 032 * @Immutable (has mutable data but it is write-only) 033 */ 034public final class IOUtils { 035 036 private static final int COPY_BUF_SIZE = 8024; 037 private static final int SKIP_BUF_SIZE = 4096; 038 039 // This buffer does not need to be synchronised because it is write only; the contents are ignored 040 // Does not affect Immutability 041 private static final byte[] SKIP_BUF = new byte[SKIP_BUF_SIZE]; 042 043 /** Private constructor to prevent instantiation of this utility class. */ 044 private IOUtils(){ 045 } 046 047 /** 048 * Copies the content of a InputStream into an OutputStream. 049 * Uses a default buffer size of 8024 bytes. 050 * 051 * @param input 052 * the InputStream to copy 053 * @param output 054 * the target Stream 055 * @return the number of bytes copied 056 * @throws IOException 057 * if an error occurs 058 */ 059 public static long copy(final InputStream input, final OutputStream output) throws IOException { 060 return copy(input, output, COPY_BUF_SIZE); 061 } 062 063 /** 064 * Copies the content of a InputStream into an OutputStream 065 * 066 * @param input 067 * the InputStream to copy 068 * @param output 069 * the target Stream 070 * @param buffersize 071 * the buffer size to use 072 * @return the number of bytes copied 073 * @throws IOException 074 * if an error occurs 075 */ 076 public static long copy(final InputStream input, final OutputStream output, final int buffersize) throws IOException { 077 final byte[] buffer = new byte[buffersize]; 078 int n = 0; 079 long count=0; 080 while (-1 != (n = input.read(buffer))) { 081 output.write(buffer, 0, n); 082 count += n; 083 } 084 return count; 085 } 086 087 /** 088 * Skips the given number of bytes by repeatedly invoking skip on 089 * the given input stream if necessary. 090 * 091 * <p>In a case where the stream's skip() method returns 0 before 092 * the requested number of bytes has been skip this implementation 093 * will fall back to using the read() method.</p> 094 * 095 * <p>This method will only skip less than the requested number of 096 * bytes if the end of the input stream has been reached.</p> 097 * 098 * @param input stream to skip bytes in 099 * @param numToSkip the number of bytes to skip 100 * @return the number of bytes actually skipped 101 * @throws IOException on error 102 */ 103 public static long skip(final InputStream input, long numToSkip) throws IOException { 104 final long available = numToSkip; 105 while (numToSkip > 0) { 106 final long skipped = input.skip(numToSkip); 107 if (skipped == 0) { 108 break; 109 } 110 numToSkip -= skipped; 111 } 112 113 while (numToSkip > 0) { 114 final int read = readFully(input, SKIP_BUF, 0, 115 (int) Math.min(numToSkip, SKIP_BUF_SIZE)); 116 if (read < 1) { 117 break; 118 } 119 numToSkip -= read; 120 } 121 return available - numToSkip; 122 } 123 124 /** 125 * Reads as much from input as possible to fill the given array. 126 * 127 * <p>This method may invoke read repeatedly to fill the array and 128 * only read less bytes than the length of the array if the end of 129 * the stream has been reached.</p> 130 * 131 * @param input stream to read from 132 * @param b buffer to fill 133 * @return the number of bytes actually read 134 * @throws IOException on error 135 */ 136 public static int readFully(final InputStream input, final byte[] b) throws IOException { 137 return readFully(input, b, 0, b.length); 138 } 139 140 /** 141 * Reads as much from input as possible to fill the given array 142 * with the given amount of bytes. 143 * 144 * <p>This method may invoke read repeatedly to read the bytes and 145 * only read less bytes than the requested length if the end of 146 * the stream has been reached.</p> 147 * 148 * @param input stream to read from 149 * @param b buffer to fill 150 * @param offset offset into the buffer to start filling at 151 * @param len of bytes to read 152 * @return the number of bytes actually read 153 * @throws IOException 154 * if an I/O error has occurred 155 */ 156 public static int readFully(final InputStream input, final byte[] b, final int offset, final int len) 157 throws IOException { 158 if (len < 0 || offset < 0 || len + offset > b.length) { 159 throw new IndexOutOfBoundsException(); 160 } 161 int count = 0, x = 0; 162 while (count != len) { 163 x = input.read(b, offset + count, len - count); 164 if (x == -1) { 165 break; 166 } 167 count += x; 168 } 169 return count; 170 } 171 172 /** 173 * Reads {@code b.remaining()} bytes from the given channel 174 * starting at the current channel's position. 175 * 176 * <p>This method reads repeatedly from the channel until the 177 * requested number of bytes are read. This method blocks until 178 * the requested number of bytes are read, the end of the channel 179 * is detected, or an exception is thrown.</p> 180 * 181 * @param channel the channel to read from 182 * @param b the buffer into which the data is read. 183 * @throws IOException - if an I/O error occurs. 184 * @throws EOFException - if the channel reaches the end before reading all the bytes. 185 */ 186 public static void readFully(ReadableByteChannel channel, ByteBuffer b) throws IOException { 187 final int expectedLength = b.remaining(); 188 int read = 0; 189 while (read < expectedLength) { 190 int readNow = channel.read(b); 191 if (readNow <= 0) { 192 break; 193 } 194 read += readNow; 195 } 196 if (read < expectedLength) { 197 throw new EOFException(); 198 } 199 } 200 201 // toByteArray(InputStream) copied from: 202 // commons/proper/io/trunk/src/main/java/org/apache/commons/io/IOUtils.java?revision=1428941 203 // January 8th, 2013 204 // 205 // Assuming our copy() works just as well as theirs! :-) 206 207 /** 208 * Gets the contents of an <code>InputStream</code> as a <code>byte[]</code>. 209 * <p> 210 * This method buffers the input internally, so there is no need to use a 211 * <code>BufferedInputStream</code>. 212 * 213 * @param input the <code>InputStream</code> to read from 214 * @return the requested byte array 215 * @throws NullPointerException if the input is null 216 * @throws IOException if an I/O error occurs 217 * @since 1.5 218 */ 219 public static byte[] toByteArray(final InputStream input) throws IOException { 220 final ByteArrayOutputStream output = new ByteArrayOutputStream(); 221 copy(input, output); 222 return output.toByteArray(); 223 } 224 225 /** 226 * Closes the given Closeable and swallows any IOException that may occur. 227 * @param c Closeable to close, can be null 228 * @since 1.7 229 */ 230 public static void closeQuietly(final Closeable c) { 231 if (c != null) { 232 try { 233 c.close(); 234 } catch (final IOException ignored) { // NOPMD 235 } 236 } 237 } 238}