• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied.  See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 package org.apache.commons.compress.utils;
20 
21 import java.io.ByteArrayOutputStream;
22 import java.io.Closeable;
23 import java.io.EOFException;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.OutputStream;
27 import java.nio.ByteBuffer;
28 import java.nio.channels.ReadableByteChannel;
29 
30 /**
31  * Utility functions
32  * @Immutable (has mutable data but it is write-only)
33  */
34 public final class IOUtils {
35 
36     private static final int COPY_BUF_SIZE = 8024;
37     private static final int SKIP_BUF_SIZE = 4096;
38 
39     // This buffer does not need to be synchronised because it is write only; the contents are ignored
40     // Does not affect Immutability
41     private static final byte[] SKIP_BUF = new byte[SKIP_BUF_SIZE];
42 
43     /** Private constructor to prevent instantiation of this utility class. */
IOUtils()44     private IOUtils(){
45     }
46 
47     /**
48      * Copies the content of a InputStream into an OutputStream.
49      * Uses a default buffer size of 8024 bytes.
50      *
51      * @param input
52      *            the InputStream to copy
53      * @param output
54      *            the target Stream
55      * @return the number of bytes copied
56      * @throws IOException
57      *             if an error occurs
58      */
copy(final InputStream input, final OutputStream output)59     public static long copy(final InputStream input, final OutputStream output) throws IOException {
60         return copy(input, output, COPY_BUF_SIZE);
61     }
62 
63     /**
64      * Copies the content of a InputStream into an OutputStream
65      *
66      * @param input
67      *            the InputStream to copy
68      * @param output
69      *            the target Stream
70      * @param buffersize
71      *            the buffer size to use, must be bigger than 0
72      * @return the number of bytes copied
73      * @throws IOException
74      *             if an error occurs
75      * @throws IllegalArgumentException
76      *             if buffersize is smaller than or equal to 0
77      */
copy(final InputStream input, final OutputStream output, final int buffersize)78     public static long copy(final InputStream input, final OutputStream output, final int buffersize) throws IOException {
79         if (buffersize < 1) {
80             throw new IllegalArgumentException("buffersize must be bigger than 0");
81         }
82         final byte[] buffer = new byte[buffersize];
83         int n = 0;
84         long count=0;
85         while (-1 != (n = input.read(buffer))) {
86             output.write(buffer, 0, n);
87             count += n;
88         }
89         return count;
90     }
91 
92     /**
93      * Skips the given number of bytes by repeatedly invoking skip on
94      * the given input stream if necessary.
95      *
96      * <p>In a case where the stream's skip() method returns 0 before
97      * the requested number of bytes has been skip this implementation
98      * will fall back to using the read() method.</p>
99      *
100      * <p>This method will only skip less than the requested number of
101      * bytes if the end of the input stream has been reached.</p>
102      *
103      * @param input stream to skip bytes in
104      * @param numToSkip the number of bytes to skip
105      * @return the number of bytes actually skipped
106      * @throws IOException on error
107      */
skip(final InputStream input, long numToSkip)108     public static long skip(final InputStream input, long numToSkip) throws IOException {
109         final long available = numToSkip;
110         while (numToSkip > 0) {
111             final long skipped = input.skip(numToSkip);
112             if (skipped == 0) {
113                 break;
114             }
115             numToSkip -= skipped;
116         }
117 
118         while (numToSkip > 0) {
119             final int read = readFully(input, SKIP_BUF, 0,
120                                  (int) Math.min(numToSkip, SKIP_BUF_SIZE));
121             if (read < 1) {
122                 break;
123             }
124             numToSkip -= read;
125         }
126         return available - numToSkip;
127     }
128 
129     /**
130      * Reads as much from input as possible to fill the given array.
131      *
132      * <p>This method may invoke read repeatedly to fill the array and
133      * only read less bytes than the length of the array if the end of
134      * the stream has been reached.</p>
135      *
136      * @param input stream to read from
137      * @param b buffer to fill
138      * @return the number of bytes actually read
139      * @throws IOException on error
140      */
readFully(final InputStream input, final byte[] b)141     public static int readFully(final InputStream input, final byte[] b) throws IOException {
142         return readFully(input, b, 0, b.length);
143     }
144 
145     /**
146      * Reads as much from input as possible to fill the given array
147      * with the given amount of bytes.
148      *
149      * <p>This method may invoke read repeatedly to read the bytes and
150      * only read less bytes than the requested length if the end of
151      * the stream has been reached.</p>
152      *
153      * @param input stream to read from
154      * @param b buffer to fill
155      * @param offset offset into the buffer to start filling at
156      * @param len of bytes to read
157      * @return the number of bytes actually read
158      * @throws IOException
159      *             if an I/O error has occurred
160      */
readFully(final InputStream input, final byte[] b, final int offset, final int len)161     public static int readFully(final InputStream input, final byte[] b, final int offset, final int len)
162         throws IOException {
163         if (len < 0 || offset < 0 || len + offset > b.length) {
164             throw new IndexOutOfBoundsException();
165         }
166         int count = 0, x = 0;
167         while (count != len) {
168             x = input.read(b, offset + count, len - count);
169             if (x == -1) {
170                 break;
171             }
172             count += x;
173         }
174         return count;
175     }
176 
177     /**
178      * Reads {@code b.remaining()} bytes from the given channel
179      * starting at the current channel's position.
180      *
181      * <p>This method reads repeatedly from the channel until the
182      * requested number of bytes are read. This method blocks until
183      * the requested number of bytes are read, the end of the channel
184      * is detected, or an exception is thrown.</p>
185      *
186      * @param channel the channel to read from
187      * @param b the buffer into which the data is read.
188      * @throws IOException - if an I/O error occurs.
189      * @throws EOFException - if the channel reaches the end before reading all the bytes.
190      */
readFully(ReadableByteChannel channel, ByteBuffer b)191     public static void readFully(ReadableByteChannel channel, ByteBuffer b) throws IOException {
192         final int expectedLength = b.remaining();
193         int read = 0;
194         while (read < expectedLength) {
195             int readNow = channel.read(b);
196             if (readNow <= 0) {
197                 break;
198             }
199             read += readNow;
200         }
201         if (read < expectedLength) {
202             throw new EOFException();
203         }
204     }
205 
206     // toByteArray(InputStream) copied from:
207     // commons/proper/io/trunk/src/main/java/org/apache/commons/io/IOUtils.java?revision=1428941
208     // January 8th, 2013
209     //
210     // Assuming our copy() works just as well as theirs!  :-)
211 
212     /**
213      * Gets the contents of an <code>InputStream</code> as a <code>byte[]</code>.
214      * <p>
215      * This method buffers the input internally, so there is no need to use a
216      * <code>BufferedInputStream</code>.
217      *
218      * @param input  the <code>InputStream</code> to read from
219      * @return the requested byte array
220      * @throws NullPointerException if the input is null
221      * @throws IOException if an I/O error occurs
222      * @since 1.5
223      */
toByteArray(final InputStream input)224     public static byte[] toByteArray(final InputStream input) throws IOException {
225         final ByteArrayOutputStream output = new ByteArrayOutputStream();
226         copy(input, output);
227         return output.toByteArray();
228     }
229 
230     /**
231      * Closes the given Closeable and swallows any IOException that may occur.
232      * @param c Closeable to close, can be null
233      * @since 1.7
234      */
closeQuietly(final Closeable c)235     public static void closeQuietly(final Closeable c) {
236         if (c != null) {
237             try {
238                 c.close();
239             } catch (final IOException ignored) { // NOPMD
240             }
241         }
242     }
243 }
244