View Javadoc
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   *     https://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   */
20  
21  package org.apache.directory.api.util;
22  
23  
24  import java.io.BufferedReader;
25  import java.io.Closeable;
26  import java.io.IOException;
27  import java.io.InputStream;
28  import java.io.InputStreamReader;
29  import java.io.OutputStream;
30  import java.io.Reader;
31  import java.io.Writer;
32  import java.nio.charset.Charset;
33  import java.util.ArrayList;
34  import java.util.List;
35  
36  import org.apache.directory.api.i18n.I18n;
37  
38  
39  /**
40   * This code comes from Apache commons.io library.
41   * 
42   * Origin of code: Excalibur, Alexandria, Tomcat, Commons-Utils.
43   *
44   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
45   */
46  public final class IOUtils
47  {
48      /**
49       * The default buffer size ({@value}) to use for
50       * {@link #copyLarge(InputStream, OutputStream)}
51       * and
52       * {@link #copyLarge(Reader, Writer)}
53       */
54      private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
55  
56      /** The end of file */
57      private static final int EOF = -1;
58  
59  
60      /**
61       * Creates a new instance of FileUtils.
62       */
63      private IOUtils()
64      {
65          // Nothing to do.
66      }
67  
68  
69      /**
70      * Closes an <code>InputStream</code> unconditionally.
71      * <p>
72      * Equivalent to {@link InputStream#close()}, except any exceptions will be ignored.
73      * This is typically used in finally blocks.
74      * <p>
75      * Example code:
76      * <pre>
77      *   byte[] data = new byte[1024];
78      *   InputStream in = null;
79      *   try {
80      *       in = new FileInputStream("foo.txt");
81      *       in.read(data);
82      *       in.close(); //close errors are handled
83      *   } catch (Exception e) {
84      *       // error handling
85      *   } finally {
86      *       IOUtils.closeQuietly(in);
87      *   }
88      * </pre>
89      *
90      * @param input  the InputStream to close, may be null or already closed
91      */
92      public static void closeQuietly( InputStream input )
93      {
94          closeQuietly( ( Closeable ) input );
95      }
96  
97  
98      /**
99       * Closes a <code>Closeable</code> unconditionally.
100      * <p>
101      * Equivalent to {@link Closeable#close()}, except any exceptions will be ignored. This is typically used in
102      * finally blocks.
103      * <p>
104      * Example code:
105      * 
106      * <pre>
107      * Closeable closeable = null;
108      * try {
109      *     closeable = new FileReader(&quot;foo.txt&quot;);
110      *     // process closeable
111      *     closeable.close();
112      * } catch (Exception e) {
113      *     // error handling
114      * } finally {
115      *     IOUtils.closeQuietly(closeable);
116      * }
117      * </pre>
118      * 
119      * Closing all streams:
120      * 
121      * <pre>
122      * try {
123      *     return IOUtils.copy(inputStream, outputStream);
124      * } finally {
125      *     IOUtils.closeQuietly(inputStream);
126      *     IOUtils.closeQuietly(outputStream);
127      * }
128      * </pre>
129      * 
130      * @param closeables the objects to close, may be null or already closed
131      * @since 2.5
132      */
133     public static void closeQuietly( Closeable... closeables )
134     {
135         if ( closeables == null )
136         {
137             return;
138         }
139 
140         for ( Closeable closeable : closeables )
141         {
142             closeQuietly( closeable );
143         }
144     }
145 
146 
147     /**
148      * Closes a <code>Closeable</code> unconditionally.
149      * <p>
150      * Equivalent to {@link Closeable#close()}, except any exceptions will be ignored. This is typically used in
151      * finally blocks.
152      * <p>
153      * Example code:
154      * 
155      * <pre>
156      * Closeable closeable = null;
157      * try {
158      *     closeable = new FileReader(&quot;foo.txt&quot;);
159      *     // process closeable
160      *     closeable.close();
161      * } catch (Exception e) {
162      *     // error handling
163      * } finally {
164      *     IOUtils.closeQuietly(closeable);
165      * }
166      * </pre>
167      * 
168      * Closing all streams:
169      * 
170      * <pre>
171      * try {
172      *     return IOUtils.copy(inputStream, outputStream);
173      * } finally {
174      *     IOUtils.closeQuietly(inputStream);
175      *     IOUtils.closeQuietly(outputStream);
176      * }
177      * </pre>
178      * 
179      * @param closeable
180      *            the objects to close, may be null or already closed
181      * @since 2.0
182      */
183     public static void closeQuietly( Closeable closeable )
184     {
185         try
186         {
187             if ( closeable != null )
188             {
189                 closeable.close();
190             }
191         }
192         catch ( IOException ioe )
193         {
194             // ignore
195         }
196     }
197 
198 
199     /**
200     * Gets the contents of an <code>InputStream</code> as a String
201     * using the specified character encoding.
202     * <p>
203     * This method buffers the input internally, so there is no need to use a
204     * <code>BufferedInputStream</code>.
205     * </p>
206     * @param input  the <code>InputStream</code> to read from
207     * @param encoding  the encoding to use, null means platform default
208     * @return the requested String
209     * @throws NullPointerException if the input is null
210     * @throws IOException if an I/O error occurs
211     * @since 2.3
212     */
213     public static String toString( InputStream input, Charset encoding ) throws IOException
214     {
215         StringBuilderWriter sw = new StringBuilderWriter();
216         copy( input, sw, encoding );
217 
218         return sw.toString();
219     }
220 
221 
222     /**
223      * Returns the given Charset or the default Charset if the given Charset is null.
224      * 
225      * @param charset A charset or null.
226      * @return the given Charset or the default Charset if the given Charset is null
227      */
228     public static Charset toCharset( Charset charset )
229     {
230         return charset == null ? Charset.defaultCharset() : charset;
231     }
232 
233 
234     /**
235      * Returns a Charset for the named charset. If the name is null, return the default Charset.
236      * 
237      * @param charset The name of the requested charset, may be null.
238      * @return a Charset for the named charset
239      */
240     public static Charset toCharset( String charset )
241     {
242         return charset == null ? Charset.defaultCharset() : Charset.forName( charset );
243     }
244 
245 
246     /**
247      * Copies bytes from an <code>InputStream</code> to chars on a
248      * <code>Writer</code> using the specified character encoding.
249      * <p>
250      * This method buffers the input internally, so there is no need to use a
251      * <code>BufferedInputStream</code>.
252      * <p>
253      * This method uses {@link InputStreamReader}.
254      *
255      * @param input  the <code>InputStream</code> to read from
256      * @param output  the <code>Writer</code> to write to
257      * @param inputEncoding  the encoding to use for the input stream, null means platform default
258      * @throws NullPointerException if the input or output is null
259      * @throws IOException if an I/O error occurs
260      * @since 2.3
261      */
262     public static void copy( InputStream input, Writer output, Charset inputEncoding ) throws IOException
263     {
264         InputStreamReader in = new InputStreamReader( input, toCharset( inputEncoding ) );
265         copy( in, output );
266     }
267 
268 
269     /**
270      * Copies chars from a <code>Reader</code> to a <code>Writer</code>.
271      * <p>
272      * This method buffers the input internally, so there is no need to use a
273      * <code>BufferedReader</code>.
274      * <p>
275      * Large streams (over 2GB) will return a chars copied value of
276      * <code>-1</code> after the copy has completed since the correct
277      * number of chars cannot be returned as an int. For large streams
278      * use the <code>copyLarge(Reader, Writer)</code> method.
279      *
280      * @param input  the <code>Reader</code> to read from
281      * @param output  the <code>Writer</code> to write to
282      * @return the number of characters copied, or -1 if &gt; Integer.MAX_VALUE
283      * @throws NullPointerException if the input or output is null
284      * @throws IOException if an I/O error occurs
285      * @since 1.1
286      */
287     public static int copy( Reader input, Writer output ) throws IOException
288     {
289         long count = copyLarge( input, output );
290 
291         if ( count > Integer.MAX_VALUE )
292         {
293             return -1;
294         }
295 
296         return ( int ) count;
297     }
298 
299     
300     /**
301      * Copies bytes from an <code>InputStream</code> to an
302      * <code>OutputStream</code>.
303      * <p>
304      * This method buffers the input internally, so there is no need to use a
305      * <code>BufferedInputStream</code>.
306      * <p>
307      * Large streams (over 2GB) will return a bytes copied value of
308      * <code>-1</code> after the copy has completed since the correct
309      * number of bytes cannot be returned as an int. For large streams
310      * use the <code>copyLarge(InputStream, OutputStream)</code> method.
311      *
312      * @param input  the <code>InputStream</code> to read from
313      * @param output  the <code>OutputStream</code> to write to
314      * @return the number of bytes copied, or -1 if &gt; Integer.MAX_VALUE
315      * @throws NullPointerException if the input or output is null
316      * @throws IOException if an I/O error occurs
317      * @since 1.1
318      */
319     public static int copy( InputStream input, OutputStream output ) throws IOException 
320     {
321         long count = copyLarge( input, output );
322         
323         if ( count > Integer.MAX_VALUE ) 
324         {
325             return -1;
326         }
327         
328         return ( int ) count;
329     }
330     
331     
332     /**
333      * Copies bytes from an <code>InputStream</code> to an <code>OutputStream</code> using an internal buffer of the
334      * given size.
335      * <p>
336      * This method buffers the input internally, so there is no need to use a <code>BufferedInputStream</code>.
337      * <p>
338      *
339      * @param input
340      *            the <code>InputStream</code> to read from
341      * @param output
342      *            the <code>OutputStream</code> to write to
343      * @param bufferSize
344      *            the bufferSize used to copy from the input to the output
345      * @return the number of bytes copied
346      * @throws NullPointerException
347      *             if the input or output is null
348      * @throws IOException
349      *             if an I/O error occurs
350      * @since 2.5
351      */
352     public static long copy( InputStream input, OutputStream output, int bufferSize ) throws IOException 
353     {
354         return copyLarge( input, output, new byte[bufferSize] );
355     }
356 
357 
358     /**
359      * Copies chars from a large (over 2GB) <code>Reader</code> to a <code>Writer</code>.
360      * <p>
361      * This method buffers the input internally, so there is no need to use a
362      * <code>BufferedReader</code>.
363      * <p>
364      * The buffer size is given by #DEFAULT_BUFFER_SIZE.
365      *
366      * @param input  the <code>Reader</code> to read from
367      * @param output  the <code>Writer</code> to write to
368      * @return the number of characters copied
369      * @throws NullPointerException if the input or output is null
370      * @throws IOException if an I/O error occurs
371      * @since 1.3
372      */
373     public static long copyLarge( Reader input, Writer output ) throws IOException
374     {
375         return copyLarge( input, output, new char[DEFAULT_BUFFER_SIZE] );
376     }
377     
378     
379     /**
380      * Copies bytes from a large (over 2GB) <code>InputStream</code> to an
381      * <code>OutputStream</code>.
382      * <p>
383      * This method buffers the input internally, so there is no need to use a
384      * <code>BufferedInputStream</code>.
385      * <p>
386      * The buffer size is given by #DEFAULT_BUFFER_SIZE.
387      *
388      * @param input  the <code>InputStream</code> to read from
389      * @param output  the <code>OutputStream</code> to write to
390      * @return the number of bytes copied
391      * @throws NullPointerException if the input or output is null
392      * @throws IOException if an I/O error occurs
393      * @since 1.3
394      */
395     public static long copyLarge( InputStream input, OutputStream output ) throws IOException 
396     {
397         return copy( input, output, DEFAULT_BUFFER_SIZE );
398     }
399 
400     
401     /**
402      * Copies bytes from a large (over 2GB) <code>InputStream</code> to an
403      * <code>OutputStream</code>.
404      * <p>
405      * This method uses the provided buffer, so there is no need to use a
406      * <code>BufferedInputStream</code>.
407      * <p>
408      *
409      * @param input  the <code>InputStream</code> to read from
410      * @param output  the <code>OutputStream</code> to write to
411      * @param buffer the buffer to use for the copy
412      * @return the number of bytes copied
413      * @throws NullPointerException if the input or output is null
414      * @throws IOException if an I/O error occurs
415      * @since 2.2
416      */
417     public static long copyLarge( InputStream input, OutputStream output, byte[] buffer ) throws IOException 
418     {
419         long count = 0;
420         int n;
421         
422         while ( EOF != ( n = input.read( buffer ) ) ) 
423         {
424             output.write( buffer, 0, n );
425             count += n;
426         }
427         
428         return count;
429     }
430 
431 
432     /**
433      * Copies chars from a large (over 2GB) <code>Reader</code> to a <code>Writer</code>.
434      * <p>
435      * This method uses the provided buffer, so there is no need to use a
436      * <code>BufferedReader</code>.
437      * <p>
438      *
439      * @param input  the <code>Reader</code> to read from
440      * @param output  the <code>Writer</code> to write to
441      * @param buffer the buffer to be used for the copy
442      * @return the number of characters copied
443      * @throws NullPointerException if the input or output is null
444      * @throws IOException if an I/O error occurs
445      * @since 2.2
446      */
447     public static long copyLarge( Reader input, Writer output, char[] buffer ) throws IOException
448     {
449         long count = 0;
450         int n;
451 
452         while ( EOF != ( n = input.read( buffer ) ) )
453         {
454             output.write( buffer, 0, n );
455             count += n;
456         }
457 
458         return count;
459     }
460 
461 
462     /**
463      * Writes chars from a <code>String</code> to bytes on an
464      * <code>OutputStream</code> using the specified character encoding.
465      * <p>
466      * This method uses {@link String#getBytes(String)}.
467      *
468      * @param data  the <code>String</code> to write, null ignored
469      * @param output  the <code>OutputStream</code> to write to
470      * @param encoding  the encoding to use, null means platform default
471      * @throws NullPointerException if output is null
472      * @throws IOException if an I/O error occurs
473      * @since 2.3
474      */
475     public static void write( String data, OutputStream output, Charset encoding ) throws IOException
476     {
477         if ( data != null )
478         {
479             output.write( data.getBytes( toCharset( encoding ) ) );
480         }
481     }
482 
483 
484     /**
485      * Gets the contents of an <code>InputStream</code> as a <code>byte[]</code>.
486      * Use this method instead of <code>toByteArray(InputStream)</code>
487      * when <code>InputStream</code> size is known
488      * @param input the <code>InputStream</code> to read from
489      * @param size the size of <code>InputStream</code>
490      * @return the requested byte array
491      * @throws IOException if an I/O error occurs or <code>InputStream</code> size differ from parameter size
492      * @throws IllegalArgumentException if size is less than zero
493      * @since 2.1
494      */
495     public static byte[] toByteArray( InputStream input, int size ) throws IOException
496     {
497         if ( size < 0 )
498         {
499             throw new IllegalArgumentException( I18n.err( I18n.ERR_17070_SIZE_POSITIVE, size ) );
500         }
501 
502         if ( size == 0 )
503         {
504             return new byte[0];
505         }
506 
507         byte[] data = new byte[size];
508         int offset = 0;
509         int readed = input.read( data, offset, size - offset );
510 
511         while ( offset < size && ( readed != EOF ) )
512         {
513             offset += readed;
514             readed = input.read( data, offset, size - offset );
515         }
516 
517         if ( offset != size )
518         {
519             throw new IOException( I18n.err( I18n.ERR_17071_UNEXPECTED_SIZE, offset, size ) );
520         }
521 
522         return data;
523     }
524     
525     
526     /**
527      * Gets contents of an <code>InputStream</code> as a <code>byte[]</code>.
528      * Use this method instead of <code>toByteArray(InputStream)</code>
529      * when <code>InputStream</code> size is known.
530      * <b>NOTE:</b> the method checks that the length can safely be cast to an int without truncation
531      * before using {@link IOUtils#toByteArray(java.io.InputStream, int)} to read into the byte array.
532      * (Arrays can have no more than Integer.MAX_VALUE entries anyway)
533      *
534      * @param input the <code>InputStream</code> to read from
535      * @param size the size of <code>InputStream</code>
536      * @return the requested byte array
537      * @throws IOException if an I/O error occurs or <code>InputStream</code> size differ from parameter size
538      * @throws IllegalArgumentException if size is less than zero or size is greater than Integer.MAX_VALUE
539      * @see IOUtils#toByteArray(java.io.InputStream, int)
540      * @since 2.1
541      */
542     public static byte[] toByteArray( InputStream input, long size ) throws IOException 
543     {
544 
545       if ( size > Integer.MAX_VALUE ) 
546       {
547           throw new IllegalArgumentException( I18n.err( I18n.ERR_17072_INTEGER_OVERFLOW, size ) );
548       }
549 
550       return toByteArray( input, ( int ) size );
551     }
552     
553     
554     /**
555      * Gets the contents of an <code>InputStream</code> as a list of Strings,
556      * one entry per line, using the specified character encoding.
557      * <p>
558      * This method buffers the input internally, so there is no need to use a
559      * <code>BufferedInputStream</code>.
560      *
561      * @param input  the <code>InputStream</code> to read from, not null
562      * @param encoding  the encoding to use, null means platform default
563      * @return the list of Strings, never null
564      * @throws NullPointerException if the input is null
565      * @throws IOException if an I/O error occurs
566      * @since 2.3
567      */
568     public static List<String> readLines( InputStream input, Charset encoding ) throws IOException 
569     {
570         InputStreamReader reader = new InputStreamReader( input, toCharset( encoding ) );
571         
572         return readLines( reader );
573     }
574     
575     
576     /**
577      * Gets the contents of a <code>Reader</code> as a list of Strings,
578      * one entry per line.
579      * <p>
580      * This method buffers the input internally, so there is no need to use a
581      * <code>BufferedReader</code>.
582      *
583      * @param input  the <code>Reader</code> to read from, not null
584      * @return the list of Strings, never null
585      * @throws NullPointerException if the input is null
586      * @throws IOException if an I/O error occurs
587      * @since 1.1
588      */
589     public static List<String> readLines( Reader input ) throws IOException 
590     {
591         BufferedReader reader = toBufferedReader( input );
592         List<String> list = new ArrayList<>();
593         String line = reader.readLine();
594         
595         while ( line != null ) 
596         {
597             list.add( line );
598             line = reader.readLine();
599         }
600         
601         return list;
602     }
603 
604     
605     /**
606      * Returns the given reader if it is a {@link BufferedReader}, otherwise creates a BufferedReader from the given
607      * reader.
608      *
609      * @param reader
610      *            the reader to wrap or return (not null)
611      * @return the given reader or a new {@link BufferedReader} for the given reader
612      * @since 2.2
613      * @throws NullPointerException if the input parameter is null
614      */
615     public static BufferedReader toBufferedReader( Reader reader ) 
616     {
617         return reader instanceof BufferedReader ? ( BufferedReader ) reader : new BufferedReader( reader );
618     }
619 }