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.IOException; 024import java.io.InputStream; 025import java.io.OutputStream; 026 027/** 028 * Utility functions 029 * @Immutable (has mutable data but it is write-only) 030 */ 031public final class IOUtils { 032 033 private static final int COPY_BUF_SIZE = 8024; 034 private static final int SKIP_BUF_SIZE = 4096; 035 036 // This buffer does not need to be synchronised because it is write only; the contents are ignored 037 // Does not affect Immutability 038 private static final byte[] SKIP_BUF = new byte[SKIP_BUF_SIZE]; 039 040 /** Private constructor to prevent instantiation of this utility class. */ 041 private IOUtils(){ 042 } 043 044 /** 045 * Copies the content of a InputStream into an OutputStream. 046 * Uses a default buffer size of 8024 bytes. 047 * 048 * @param input 049 * the InputStream to copy 050 * @param output 051 * the target Stream 052 * @return the number of bytes copied 053 * @throws IOException 054 * if an error occurs 055 */ 056 public static long copy(final InputStream input, final OutputStream output) throws IOException { 057 return copy(input, output, COPY_BUF_SIZE); 058 } 059 060 /** 061 * Copies the content of a InputStream into an OutputStream 062 * 063 * @param input 064 * the InputStream to copy 065 * @param output 066 * the target Stream 067 * @param buffersize 068 * the buffer size to use 069 * @return the number of bytes copied 070 * @throws IOException 071 * if an error occurs 072 */ 073 public static long copy(final InputStream input, final OutputStream output, final int buffersize) throws IOException { 074 final byte[] buffer = new byte[buffersize]; 075 int n = 0; 076 long count=0; 077 while (-1 != (n = input.read(buffer))) { 078 output.write(buffer, 0, n); 079 count += n; 080 } 081 return count; 082 } 083 084 /** 085 * Skips the given number of bytes by repeatedly invoking skip on 086 * the given input stream if necessary. 087 * 088 * <p>In a case where the stream's skip() method returns 0 before 089 * the requested number of bytes has been skip this implementation 090 * will fall back to using the read() method.</p> 091 * 092 * <p>This method will only skip less than the requested number of 093 * bytes if the end of the input stream has been reached.</p> 094 * 095 * @param input stream to skip bytes in 096 * @param numToSkip the number of bytes to skip 097 * @return the number of bytes actually skipped 098 * @throws IOException on error 099 */ 100 public static long skip(final InputStream input, long numToSkip) throws IOException { 101 final long available = numToSkip; 102 while (numToSkip > 0) { 103 final long skipped = input.skip(numToSkip); 104 if (skipped == 0) { 105 break; 106 } 107 numToSkip -= skipped; 108 } 109 110 while (numToSkip > 0) { 111 final int read = readFully(input, SKIP_BUF, 0, 112 (int) Math.min(numToSkip, SKIP_BUF_SIZE)); 113 if (read < 1) { 114 break; 115 } 116 numToSkip -= read; 117 } 118 return available - numToSkip; 119 } 120 121 /** 122 * Reads as much from input as possible to fill the given array. 123 * 124 * <p>This method may invoke read repeatedly to fill the array and 125 * only read less bytes than the length of the array if the end of 126 * the stream has been reached.</p> 127 * 128 * @param input stream to read from 129 * @param b buffer to fill 130 * @return the number of bytes actually read 131 * @throws IOException on error 132 */ 133 public static int readFully(final InputStream input, final byte[] b) throws IOException { 134 return readFully(input, b, 0, b.length); 135 } 136 137 /** 138 * Reads as much from input as possible to fill the given array 139 * with the given amount of bytes. 140 * 141 * <p>This method may invoke read repeatedly to read the bytes and 142 * only read less bytes than the requested length if the end of 143 * the stream has been reached.</p> 144 * 145 * @param input stream to read from 146 * @param b buffer to fill 147 * @param offset offset into the buffer to start filling at 148 * @param len of bytes to read 149 * @return the number of bytes actually read 150 * @throws IOException 151 * if an I/O error has occurred 152 */ 153 public static int readFully(final InputStream input, final byte[] b, final int offset, final int len) 154 throws IOException { 155 if (len < 0 || offset < 0 || len + offset > b.length) { 156 throw new IndexOutOfBoundsException(); 157 } 158 int count = 0, x = 0; 159 while (count != len) { 160 x = input.read(b, offset + count, len - count); 161 if (x == -1) { 162 break; 163 } 164 count += x; 165 } 166 return count; 167 } 168 169 // toByteArray(InputStream) copied from: 170 // commons/proper/io/trunk/src/main/java/org/apache/commons/io/IOUtils.java?revision=1428941 171 // January 8th, 2013 172 // 173 // Assuming our copy() works just as well as theirs! :-) 174 175 /** 176 * Gets the contents of an <code>InputStream</code> as a <code>byte[]</code>. 177 * <p> 178 * This method buffers the input internally, so there is no need to use a 179 * <code>BufferedInputStream</code>. 180 * 181 * @param input the <code>InputStream</code> to read from 182 * @return the requested byte array 183 * @throws NullPointerException if the input is null 184 * @throws IOException if an I/O error occurs 185 * @since 1.5 186 */ 187 public static byte[] toByteArray(final InputStream input) throws IOException { 188 final ByteArrayOutputStream output = new ByteArrayOutputStream(); 189 copy(input, output); 190 return output.toByteArray(); 191 } 192 193 /** 194 * Closes the given Closeable and swallows any IOException that may occur. 195 * @param c Closeable to close, can be null 196 * @since 1.7 197 */ 198 public static void closeQuietly(final Closeable c) { 199 if (c != null) { 200 try { 201 c.close(); 202 } catch (final IOException ignored) { // NOPMD 203 } 204 } 205 } 206}