1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17package org.apache.commons.io;
18
19import java.io.BufferedInputStream;
20import java.io.BufferedReader;
21import java.io.ByteArrayInputStream;
22import java.io.CharArrayWriter;
23import java.io.File;
24import java.io.IOException;
25import java.io.InputStream;
26import java.io.InputStreamReader;
27import java.io.OutputStream;
28import java.io.OutputStreamWriter;
29import java.io.PrintWriter;
30import java.io.Reader;
31import java.io.StringWriter;
32import java.io.Writer;
33import java.util.ArrayList;
34import java.util.Collection;
35import java.util.Iterator;
36import java.util.List;
37
38import org.apache.commons.io.output.ByteArrayOutputStream;
39
40/**
41 * General IO stream manipulation utilities.
42 * <p>
43 * This class provides static utility methods for input/output operations.
44 * <ul>
45 * <li>closeQuietly - these methods close a stream ignoring nulls and exceptions
46 * <li>toXxx/read - these methods read data from a stream
47 * <li>write - these methods write data to a stream
48 * <li>copy - these methods copy all the data from one stream to another
49 * <li>contentEquals - these methods compare the content of two streams
50 * </ul>
51 * <p>
52 * The byte-to-char methods and char-to-byte methods involve a conversion step.
53 * Two methods are provided in each case, one that uses the platform default
54 * encoding and the other which allows you to specify an encoding. You are
55 * encouraged to always specify an encoding because relying on the platform
56 * default can lead to unexpected results, for example when moving from
57 * development to production.
58 * <p>
59 * All the methods in this class that read a stream are buffered internally.
60 * This means that there is no cause to use a <code>BufferedInputStream</code>
61 * or <code>BufferedReader</code>. The default buffer size of 4K has been shown
62 * to be efficient in tests.
63 * <p>
64 * Wherever possible, the methods in this class do <em>not</em> flush or close
65 * the stream. This is to avoid making non-portable assumptions about the
66 * streams' origin and further use. Thus the caller is still responsible for
67 * closing streams after use.
68 * <p>
69 * Origin of code: Excalibur.
70 *
71 * @author Peter Donald
72 * @author Jeff Turner
73 * @author Matthew Hawthorne
74 * @author Stephen Colebourne
75 * @author Gareth Davis
76 * @author Ian Springer
77 * @author Niall Pemberton
78 * @author Sandy McArthur
79 * @version $Id: IOUtils.java 481854 2006-12-03 18:30:07Z scolebourne $
80 */
81public class IOUtils {
82    // NOTE: This class is focussed on InputStream, OutputStream, Reader and
83    // Writer. Each method should take at least one of these as a parameter,
84    // or return one of them.
85
86    /**
87     * The Unix directory separator character.
88     */
89    public static final char DIR_SEPARATOR_UNIX = '/';
90    /**
91     * The Windows directory separator character.
92     */
93    public static final char DIR_SEPARATOR_WINDOWS = '\\';
94    /**
95     * The system directory separator character.
96     */
97    public static final char DIR_SEPARATOR = File.separatorChar;
98    /**
99     * The Unix line separator string.
100     */
101    public static final String LINE_SEPARATOR_UNIX = "\n";
102    /**
103     * The Windows line separator string.
104     */
105    public static final String LINE_SEPARATOR_WINDOWS = "\r\n";
106    /**
107     * The system line separator string.
108     */
109    public static final String LINE_SEPARATOR;
110    static {
111        // avoid security issues
112        StringWriter buf = new StringWriter(4);
113        PrintWriter out = new PrintWriter(buf);
114        out.println();
115        LINE_SEPARATOR = buf.toString();
116    }
117
118    /**
119     * The default buffer size to use.
120     */
121    private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
122
123    /**
124     * Instances should NOT be constructed in standard programming.
125     */
126    public IOUtils() {
127        super();
128    }
129
130    //-----------------------------------------------------------------------
131    /**
132     * Unconditionally close an <code>Reader</code>.
133     * <p>
134     * Equivalent to {@link Reader#close()}, except any exceptions will be ignored.
135     * This is typically used in finally blocks.
136     *
137     * @param input  the Reader to close, may be null or already closed
138     */
139    public static void closeQuietly(Reader input) {
140        try {
141            if (input != null) {
142                input.close();
143            }
144        } catch (IOException ioe) {
145            // ignore
146        }
147    }
148
149    /**
150     * Unconditionally close a <code>Writer</code>.
151     * <p>
152     * Equivalent to {@link Writer#close()}, except any exceptions will be ignored.
153     * This is typically used in finally blocks.
154     *
155     * @param output  the Writer to close, may be null or already closed
156     */
157    public static void closeQuietly(Writer output) {
158        try {
159            if (output != null) {
160                output.close();
161            }
162        } catch (IOException ioe) {
163            // ignore
164        }
165    }
166
167    /**
168     * Unconditionally close an <code>InputStream</code>.
169     * <p>
170     * Equivalent to {@link InputStream#close()}, except any exceptions will be ignored.
171     * This is typically used in finally blocks.
172     *
173     * @param input  the InputStream to close, may be null or already closed
174     */
175    public static void closeQuietly(InputStream input) {
176        try {
177            if (input != null) {
178                input.close();
179            }
180        } catch (IOException ioe) {
181            // ignore
182        }
183    }
184
185    /**
186     * Unconditionally close an <code>OutputStream</code>.
187     * <p>
188     * Equivalent to {@link OutputStream#close()}, except any exceptions will be ignored.
189     * This is typically used in finally blocks.
190     *
191     * @param output  the OutputStream to close, may be null or already closed
192     */
193    public static void closeQuietly(OutputStream output) {
194        try {
195            if (output != null) {
196                output.close();
197            }
198        } catch (IOException ioe) {
199            // ignore
200        }
201    }
202
203    // read toByteArray
204    //-----------------------------------------------------------------------
205    /**
206     * Get the contents of an <code>InputStream</code> as a <code>byte[]</code>.
207     * <p>
208     * This method buffers the input internally, so there is no need to use a
209     * <code>BufferedInputStream</code>.
210     *
211     * @param input  the <code>InputStream</code> to read from
212     * @return the requested byte array
213     * @throws NullPointerException if the input is null
214     * @throws IOException if an I/O error occurs
215     */
216    public static byte[] toByteArray(InputStream input) throws IOException {
217        ByteArrayOutputStream output = new ByteArrayOutputStream();
218        copy(input, output);
219        return output.toByteArray();
220    }
221
222    /**
223     * Get the contents of a <code>Reader</code> as a <code>byte[]</code>
224     * using the default character encoding of the platform.
225     * <p>
226     * This method buffers the input internally, so there is no need to use a
227     * <code>BufferedReader</code>.
228     *
229     * @param input  the <code>Reader</code> to read from
230     * @return the requested byte array
231     * @throws NullPointerException if the input is null
232     * @throws IOException if an I/O error occurs
233     */
234    public static byte[] toByteArray(Reader input) throws IOException {
235        ByteArrayOutputStream output = new ByteArrayOutputStream();
236        copy(input, output);
237        return output.toByteArray();
238    }
239
240    /**
241     * Get the contents of a <code>Reader</code> as a <code>byte[]</code>
242     * using the specified character encoding.
243     * <p>
244     * Character encoding names can be found at
245     * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
246     * <p>
247     * This method buffers the input internally, so there is no need to use a
248     * <code>BufferedReader</code>.
249     *
250     * @param input  the <code>Reader</code> to read from
251     * @param encoding  the encoding to use, null means platform default
252     * @return the requested byte array
253     * @throws NullPointerException if the input is null
254     * @throws IOException if an I/O error occurs
255     * @since Commons IO 1.1
256     */
257    public static byte[] toByteArray(Reader input, String encoding)
258            throws IOException {
259        ByteArrayOutputStream output = new ByteArrayOutputStream();
260        copy(input, output, encoding);
261        return output.toByteArray();
262    }
263
264    /**
265     * Get the contents of a <code>String</code> as a <code>byte[]</code>
266     * using the default character encoding of the platform.
267     * <p>
268     * This is the same as {@link String#getBytes()}.
269     *
270     * @param input  the <code>String</code> to convert
271     * @return the requested byte array
272     * @throws NullPointerException if the input is null
273     * @throws IOException if an I/O error occurs (never occurs)
274     * @deprecated Use {@link String#getBytes()}
275     */
276    @Deprecated
277    public static byte[] toByteArray(String input) throws IOException {
278        return input.getBytes();
279    }
280
281    // read char[]
282    //-----------------------------------------------------------------------
283    /**
284     * Get the contents of an <code>InputStream</code> as a character array
285     * using the default character encoding of the platform.
286     * <p>
287     * This method buffers the input internally, so there is no need to use a
288     * <code>BufferedInputStream</code>.
289     *
290     * @param is  the <code>InputStream</code> to read from
291     * @return the requested character array
292     * @throws NullPointerException if the input is null
293     * @throws IOException if an I/O error occurs
294     * @since Commons IO 1.1
295     */
296    public static char[] toCharArray(InputStream is) throws IOException {
297        CharArrayWriter output = new CharArrayWriter();
298        copy(is, output);
299        return output.toCharArray();
300    }
301
302    /**
303     * Get the contents of an <code>InputStream</code> as a character array
304     * using the specified character encoding.
305     * <p>
306     * Character encoding names can be found at
307     * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
308     * <p>
309     * This method buffers the input internally, so there is no need to use a
310     * <code>BufferedInputStream</code>.
311     *
312     * @param is  the <code>InputStream</code> to read from
313     * @param encoding  the encoding to use, null means platform default
314     * @return the requested character array
315     * @throws NullPointerException if the input is null
316     * @throws IOException if an I/O error occurs
317     * @since Commons IO 1.1
318     */
319    public static char[] toCharArray(InputStream is, String encoding)
320            throws IOException {
321        CharArrayWriter output = new CharArrayWriter();
322        copy(is, output, encoding);
323        return output.toCharArray();
324    }
325
326    /**
327     * Get the contents of a <code>Reader</code> as a character array.
328     * <p>
329     * This method buffers the input internally, so there is no need to use a
330     * <code>BufferedReader</code>.
331     *
332     * @param input  the <code>Reader</code> to read from
333     * @return the requested character array
334     * @throws NullPointerException if the input is null
335     * @throws IOException if an I/O error occurs
336     * @since Commons IO 1.1
337     */
338    public static char[] toCharArray(Reader input) throws IOException {
339        CharArrayWriter sw = new CharArrayWriter();
340        copy(input, sw);
341        return sw.toCharArray();
342    }
343
344    // read toString
345    //-----------------------------------------------------------------------
346    /**
347     * Get the contents of an <code>InputStream</code> as a String
348     * using the default character encoding of the platform.
349     * <p>
350     * This method buffers the input internally, so there is no need to use a
351     * <code>BufferedInputStream</code>.
352     *
353     * @param input  the <code>InputStream</code> to read from
354     * @return the requested String
355     * @throws NullPointerException if the input is null
356     * @throws IOException if an I/O error occurs
357     */
358    public static String toString(InputStream input) throws IOException {
359        StringWriter sw = new StringWriter();
360        copy(input, sw);
361        return sw.toString();
362    }
363
364    /**
365     * Get the contents of an <code>InputStream</code> as a String
366     * using the specified character encoding.
367     * <p>
368     * Character encoding names can be found at
369     * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
370     * <p>
371     * This method buffers the input internally, so there is no need to use a
372     * <code>BufferedInputStream</code>.
373     *
374     * @param input  the <code>InputStream</code> to read from
375     * @param encoding  the encoding to use, null means platform default
376     * @return the requested String
377     * @throws NullPointerException if the input is null
378     * @throws IOException if an I/O error occurs
379     */
380    public static String toString(InputStream input, String encoding)
381            throws IOException {
382        StringWriter sw = new StringWriter();
383        copy(input, sw, encoding);
384        return sw.toString();
385    }
386
387    /**
388     * Get the contents of a <code>Reader</code> as a String.
389     * <p>
390     * This method buffers the input internally, so there is no need to use a
391     * <code>BufferedReader</code>.
392     *
393     * @param input  the <code>Reader</code> to read from
394     * @return the requested String
395     * @throws NullPointerException if the input is null
396     * @throws IOException if an I/O error occurs
397     */
398    public static String toString(Reader input) throws IOException {
399        StringWriter sw = new StringWriter();
400        copy(input, sw);
401        return sw.toString();
402    }
403
404    /**
405     * Get the contents of a <code>byte[]</code> as a String
406     * using the default character encoding of the platform.
407     *
408     * @param input the byte array to read from
409     * @return the requested String
410     * @throws NullPointerException if the input is null
411     * @throws IOException if an I/O error occurs (never occurs)
412     * @deprecated Use {@link String#String(byte[])}
413     */
414    @Deprecated
415    public static String toString(byte[] input) throws IOException {
416        return new String(input);
417    }
418
419    /**
420     * Get the contents of a <code>byte[]</code> as a String
421     * using the specified character encoding.
422     * <p>
423     * Character encoding names can be found at
424     * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
425     *
426     * @param input the byte array to read from
427     * @param encoding  the encoding to use, null means platform default
428     * @return the requested String
429     * @throws NullPointerException if the input is null
430     * @throws IOException if an I/O error occurs (never occurs)
431     * @deprecated Use {@link String#String(byte[],String)}
432     */
433    @Deprecated
434    public static String toString(byte[] input, String encoding)
435            throws IOException {
436        if (encoding == null) {
437            return new String(input);
438        } else {
439            return new String(input, encoding);
440        }
441    }
442
443    // readLines
444    //-----------------------------------------------------------------------
445    /**
446     * Get the contents of an <code>InputStream</code> as a list of Strings,
447     * one entry per line, using the default character encoding of the platform.
448     * <p>
449     * This method buffers the input internally, so there is no need to use a
450     * <code>BufferedInputStream</code>.
451     *
452     * @param input  the <code>InputStream</code> to read from, not null
453     * @return the list of Strings, never null
454     * @throws NullPointerException if the input is null
455     * @throws IOException if an I/O error occurs
456     * @since Commons IO 1.1
457     */
458    public static List<String> readLines(InputStream input) throws IOException {
459        InputStreamReader reader = new InputStreamReader(input);
460        return readLines(reader);
461    }
462
463    /**
464     * Get the contents of an <code>InputStream</code> as a list of Strings,
465     * one entry per line, using the specified character encoding.
466     * <p>
467     * Character encoding names can be found at
468     * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
469     * <p>
470     * This method buffers the input internally, so there is no need to use a
471     * <code>BufferedInputStream</code>.
472     *
473     * @param input  the <code>InputStream</code> to read from, not null
474     * @param encoding  the encoding to use, null means platform default
475     * @return the list of Strings, never null
476     * @throws NullPointerException if the input is null
477     * @throws IOException if an I/O error occurs
478     * @since Commons IO 1.1
479     */
480    public static List<String> readLines(InputStream input, String encoding) throws IOException {
481        if (encoding == null) {
482            return readLines(input);
483        } else {
484            InputStreamReader reader = new InputStreamReader(input, encoding);
485            return readLines(reader);
486        }
487    }
488
489    /**
490     * Get the contents of a <code>Reader</code> as a list of Strings,
491     * one entry per line.
492     * <p>
493     * This method buffers the input internally, so there is no need to use a
494     * <code>BufferedReader</code>.
495     *
496     * @param input  the <code>Reader</code> to read from, not null
497     * @return the list of Strings, never null
498     * @throws NullPointerException if the input is null
499     * @throws IOException if an I/O error occurs
500     * @since Commons IO 1.1
501     */
502    public static List<String> readLines(Reader input) throws IOException {
503        BufferedReader reader = new BufferedReader(input);
504        List<String> list = new ArrayList<String>();
505        String line = reader.readLine();
506        while (line != null) {
507            list.add(line);
508            line = reader.readLine();
509        }
510        return list;
511    }
512
513    // lineIterator
514    //-----------------------------------------------------------------------
515    /**
516     * Return an Iterator for the lines in a <code>Reader</code>.
517     * <p>
518     * <code>LineIterator</code> holds a reference to the open
519     * <code>Reader</code> specified here. When you have finished with the
520     * iterator you should close the reader to free internal resources.
521     * This can be done by closing the reader directly, or by calling
522     * {@link LineIterator#close()} or {@link LineIterator#closeQuietly(LineIterator)}.
523     * <p>
524     * The recommended usage pattern is:
525     * <pre>
526     * try {
527     *   LineIterator it = IOUtils.lineIterator(reader);
528     *   while (it.hasNext()) {
529     *     String line = it.nextLine();
530     *     /// do something with line
531     *   }
532     * } finally {
533     *   IOUtils.closeQuietly(reader);
534     * }
535     * </pre>
536     *
537     * @param reader  the <code>Reader</code> to read from, not null
538     * @return an Iterator of the lines in the reader, never null
539     * @throws IllegalArgumentException if the reader is null
540     * @since Commons IO 1.2
541     */
542    public static LineIterator lineIterator(Reader reader) {
543        return new LineIterator(reader);
544    }
545
546    /**
547     * Return an Iterator for the lines in an <code>InputStream</code>, using
548     * the character encoding specified (or default encoding if null).
549     * <p>
550     * <code>LineIterator</code> holds a reference to the open
551     * <code>InputStream</code> specified here. When you have finished with
552     * the iterator you should close the stream to free internal resources.
553     * This can be done by closing the stream directly, or by calling
554     * {@link LineIterator#close()} or {@link LineIterator#closeQuietly(LineIterator)}.
555     * <p>
556     * The recommended usage pattern is:
557     * <pre>
558     * try {
559     *   LineIterator it = IOUtils.lineIterator(stream, "UTF-8");
560     *   while (it.hasNext()) {
561     *     String line = it.nextLine();
562     *     /// do something with line
563     *   }
564     * } finally {
565     *   IOUtils.closeQuietly(stream);
566     * }
567     * </pre>
568     *
569     * @param input  the <code>InputStream</code> to read from, not null
570     * @param encoding  the encoding to use, null means platform default
571     * @return an Iterator of the lines in the reader, never null
572     * @throws IllegalArgumentException if the input is null
573     * @throws IOException if an I/O error occurs, such as if the encoding is invalid
574     * @since Commons IO 1.2
575     */
576    public static LineIterator lineIterator(InputStream input, String encoding)
577                     throws IOException {
578        Reader reader = null;
579        if (encoding == null) {
580            reader = new InputStreamReader(input);
581        } else {
582            reader = new InputStreamReader(input, encoding);
583        }
584        return new LineIterator(reader);
585    }
586
587    //-----------------------------------------------------------------------
588    /**
589     * Convert the specified string to an input stream, encoded as bytes
590     * using the default character encoding of the platform.
591     *
592     * @param input the string to convert
593     * @return an input stream
594     * @since Commons IO 1.1
595     */
596    public static InputStream toInputStream(String input) {
597        byte[] bytes = input.getBytes();
598        return new ByteArrayInputStream(bytes);
599    }
600
601    /**
602     * Convert the specified string to an input stream, encoded as bytes
603     * using the specified character encoding.
604     * <p>
605     * Character encoding names can be found at
606     * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
607     *
608     * @param input the string to convert
609     * @param encoding the encoding to use, null means platform default
610     * @throws IOException if the encoding is invalid
611     * @return an input stream
612     * @since Commons IO 1.1
613     */
614    public static InputStream toInputStream(String input, String encoding) throws IOException {
615        byte[] bytes = encoding != null ? input.getBytes(encoding) : input.getBytes();
616        return new ByteArrayInputStream(bytes);
617    }
618
619    // write byte[]
620    //-----------------------------------------------------------------------
621    /**
622     * Writes bytes from a <code>byte[]</code> to an <code>OutputStream</code>.
623     *
624     * @param data  the byte array to write, do not modify during output,
625     * null ignored
626     * @param output  the <code>OutputStream</code> to write to
627     * @throws NullPointerException if output is null
628     * @throws IOException if an I/O error occurs
629     * @since Commons IO 1.1
630     */
631    public static void write(byte[] data, OutputStream output)
632            throws IOException {
633        if (data != null) {
634            output.write(data);
635        }
636    }
637
638    /**
639     * Writes bytes from a <code>byte[]</code> to chars on a <code>Writer</code>
640     * using the default character encoding of the platform.
641     * <p>
642     * This method uses {@link String#String(byte[])}.
643     *
644     * @param data  the byte array to write, do not modify during output,
645     * null ignored
646     * @param output  the <code>Writer</code> to write to
647     * @throws NullPointerException if output is null
648     * @throws IOException if an I/O error occurs
649     * @since Commons IO 1.1
650     */
651    public static void write(byte[] data, Writer output) throws IOException {
652        if (data != null) {
653            output.write(new String(data));
654        }
655    }
656
657    /**
658     * Writes bytes from a <code>byte[]</code> to chars on a <code>Writer</code>
659     * using the specified character encoding.
660     * <p>
661     * Character encoding names can be found at
662     * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
663     * <p>
664     * This method uses {@link String#String(byte[], String)}.
665     *
666     * @param data  the byte array to write, do not modify during output,
667     * null ignored
668     * @param output  the <code>Writer</code> to write to
669     * @param encoding  the encoding to use, null means platform default
670     * @throws NullPointerException if output is null
671     * @throws IOException if an I/O error occurs
672     * @since Commons IO 1.1
673     */
674    public static void write(byte[] data, Writer output, String encoding)
675            throws IOException {
676        if (data != null) {
677            if (encoding == null) {
678                write(data, output);
679            } else {
680                output.write(new String(data, encoding));
681            }
682        }
683    }
684
685    // write char[]
686    //-----------------------------------------------------------------------
687    /**
688     * Writes chars from a <code>char[]</code> to a <code>Writer</code>
689     * using the default character encoding of the platform.
690     *
691     * @param data  the char array to write, do not modify during output,
692     * null ignored
693     * @param output  the <code>Writer</code> to write to
694     * @throws NullPointerException if output is null
695     * @throws IOException if an I/O error occurs
696     * @since Commons IO 1.1
697     */
698    public static void write(char[] data, Writer output) throws IOException {
699        if (data != null) {
700            output.write(data);
701        }
702    }
703
704    /**
705     * Writes chars from a <code>char[]</code> to bytes on an
706     * <code>OutputStream</code>.
707     * <p>
708     * This method uses {@link String#String(char[])} and
709     * {@link String#getBytes()}.
710     *
711     * @param data  the char array to write, do not modify during output,
712     * null ignored
713     * @param output  the <code>OutputStream</code> to write to
714     * @throws NullPointerException if output is null
715     * @throws IOException if an I/O error occurs
716     * @since Commons IO 1.1
717     */
718    public static void write(char[] data, OutputStream output)
719            throws IOException {
720        if (data != null) {
721            output.write(new String(data).getBytes());
722        }
723    }
724
725    /**
726     * Writes chars from a <code>char[]</code> to bytes on an
727     * <code>OutputStream</code> using the specified character encoding.
728     * <p>
729     * Character encoding names can be found at
730     * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
731     * <p>
732     * This method uses {@link String#String(char[])} and
733     * {@link String#getBytes(String)}.
734     *
735     * @param data  the char array to write, do not modify during output,
736     * null ignored
737     * @param output  the <code>OutputStream</code> to write to
738     * @param encoding  the encoding to use, null means platform default
739     * @throws NullPointerException if output is null
740     * @throws IOException if an I/O error occurs
741     * @since Commons IO 1.1
742     */
743    public static void write(char[] data, OutputStream output, String encoding)
744            throws IOException {
745        if (data != null) {
746            if (encoding == null) {
747                write(data, output);
748            } else {
749                output.write(new String(data).getBytes(encoding));
750            }
751        }
752    }
753
754    // write String
755    //-----------------------------------------------------------------------
756    /**
757     * Writes chars from a <code>String</code> to a <code>Writer</code>.
758     *
759     * @param data  the <code>String</code> to write, null ignored
760     * @param output  the <code>Writer</code> to write to
761     * @throws NullPointerException if output is null
762     * @throws IOException if an I/O error occurs
763     * @since Commons IO 1.1
764     */
765    public static void write(String data, Writer output) throws IOException {
766        if (data != null) {
767            output.write(data);
768        }
769    }
770
771    /**
772     * Writes chars from a <code>String</code> to bytes on an
773     * <code>OutputStream</code> using the default character encoding of the
774     * platform.
775     * <p>
776     * This method uses {@link String#getBytes()}.
777     *
778     * @param data  the <code>String</code> to write, null ignored
779     * @param output  the <code>OutputStream</code> to write to
780     * @throws NullPointerException if output is null
781     * @throws IOException if an I/O error occurs
782     * @since Commons IO 1.1
783     */
784    public static void write(String data, OutputStream output)
785            throws IOException {
786        if (data != null) {
787            output.write(data.getBytes());
788        }
789    }
790
791    /**
792     * Writes chars from a <code>String</code> to bytes on an
793     * <code>OutputStream</code> using the specified character encoding.
794     * <p>
795     * Character encoding names can be found at
796     * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
797     * <p>
798     * This method uses {@link String#getBytes(String)}.
799     *
800     * @param data  the <code>String</code> to write, null ignored
801     * @param output  the <code>OutputStream</code> to write to
802     * @param encoding  the encoding to use, null means platform default
803     * @throws NullPointerException if output is null
804     * @throws IOException if an I/O error occurs
805     * @since Commons IO 1.1
806     */
807    public static void write(String data, OutputStream output, String encoding)
808            throws IOException {
809        if (data != null) {
810            if (encoding == null) {
811                write(data, output);
812            } else {
813                output.write(data.getBytes(encoding));
814            }
815        }
816    }
817
818    // write StringBuffer
819    //-----------------------------------------------------------------------
820    /**
821     * Writes chars from a <code>StringBuffer</code> to a <code>Writer</code>.
822     *
823     * @param data  the <code>StringBuffer</code> to write, null ignored
824     * @param output  the <code>Writer</code> to write to
825     * @throws NullPointerException if output is null
826     * @throws IOException if an I/O error occurs
827     * @since Commons IO 1.1
828     */
829    public static void write(StringBuffer data, Writer output)
830            throws IOException {
831        if (data != null) {
832            output.write(data.toString());
833        }
834    }
835
836    /**
837     * Writes chars from a <code>StringBuffer</code> to bytes on an
838     * <code>OutputStream</code> using the default character encoding of the
839     * platform.
840     * <p>
841     * This method uses {@link String#getBytes()}.
842     *
843     * @param data  the <code>StringBuffer</code> to write, null ignored
844     * @param output  the <code>OutputStream</code> to write to
845     * @throws NullPointerException if output is null
846     * @throws IOException if an I/O error occurs
847     * @since Commons IO 1.1
848     */
849    public static void write(StringBuffer data, OutputStream output)
850            throws IOException {
851        if (data != null) {
852            output.write(data.toString().getBytes());
853        }
854    }
855
856    /**
857     * Writes chars from a <code>StringBuffer</code> to bytes on an
858     * <code>OutputStream</code> using the specified character encoding.
859     * <p>
860     * Character encoding names can be found at
861     * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
862     * <p>
863     * This method uses {@link String#getBytes(String)}.
864     *
865     * @param data  the <code>StringBuffer</code> to write, null ignored
866     * @param output  the <code>OutputStream</code> to write to
867     * @param encoding  the encoding to use, null means platform default
868     * @throws NullPointerException if output is null
869     * @throws IOException if an I/O error occurs
870     * @since Commons IO 1.1
871     */
872    public static void write(StringBuffer data, OutputStream output,
873            String encoding) throws IOException {
874        if (data != null) {
875            if (encoding == null) {
876                write(data, output);
877            } else {
878                output.write(data.toString().getBytes(encoding));
879            }
880        }
881    }
882
883    // writeLines
884    //-----------------------------------------------------------------------
885    /**
886     * Writes the <code>toString()</code> value of each item in a collection to
887     * an <code>OutputStream</code> line by line, using the default character
888     * encoding of the platform and the specified line ending.
889     *
890     * @param lines  the lines to write, null entries produce blank lines
891     * @param lineEnding  the line separator to use, null is system default
892     * @param output  the <code>OutputStream</code> to write to, not null, not closed
893     * @throws NullPointerException if the output is null
894     * @throws IOException if an I/O error occurs
895     * @since Commons IO 1.1
896     */
897    public static void writeLines(Collection<Object> lines, String lineEnding,
898            OutputStream output) throws IOException {
899        if (lines == null) {
900            return;
901        }
902        if (lineEnding == null) {
903            lineEnding = LINE_SEPARATOR;
904        }
905        for (Iterator<Object> it = lines.iterator(); it.hasNext(); ) {
906            Object line = it.next();
907            if (line != null) {
908                output.write(line.toString().getBytes());
909            }
910            output.write(lineEnding.getBytes());
911        }
912    }
913
914    /**
915     * Writes the <code>toString()</code> value of each item in a collection to
916     * an <code>OutputStream</code> line by line, using the specified character
917     * encoding and the specified line ending.
918     * <p>
919     * Character encoding names can be found at
920     * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
921     *
922     * @param lines  the lines to write, null entries produce blank lines
923     * @param lineEnding  the line separator to use, null is system default
924     * @param output  the <code>OutputStream</code> to write to, not null, not closed
925     * @param encoding  the encoding to use, null means platform default
926     * @throws NullPointerException if the output is null
927     * @throws IOException if an I/O error occurs
928     * @since Commons IO 1.1
929     */
930    public static void writeLines(Collection<Object> lines, String lineEnding,
931            OutputStream output, String encoding) throws IOException {
932        if (encoding == null) {
933            writeLines(lines, lineEnding, output);
934        } else {
935            if (lines == null) {
936                return;
937            }
938            if (lineEnding == null) {
939                lineEnding = LINE_SEPARATOR;
940            }
941            for (Iterator<Object> it = lines.iterator(); it.hasNext(); ) {
942                Object line = it.next();
943                if (line != null) {
944                    output.write(line.toString().getBytes(encoding));
945                }
946                output.write(lineEnding.getBytes(encoding));
947            }
948        }
949    }
950
951    /**
952     * Writes the <code>toString()</code> value of each item in a collection to
953     * a <code>Writer</code> line by line, using the specified line ending.
954     *
955     * @param lines  the lines to write, null entries produce blank lines
956     * @param lineEnding  the line separator to use, null is system default
957     * @param writer  the <code>Writer</code> to write to, not null, not closed
958     * @throws NullPointerException if the input is null
959     * @throws IOException if an I/O error occurs
960     * @since Commons IO 1.1
961     */
962    public static void writeLines(Collection<Object> lines, String lineEnding,
963            Writer writer) throws IOException {
964        if (lines == null) {
965            return;
966        }
967        if (lineEnding == null) {
968            lineEnding = LINE_SEPARATOR;
969        }
970        for (Iterator<Object> it = lines.iterator(); it.hasNext(); ) {
971            Object line = it.next();
972            if (line != null) {
973                writer.write(line.toString());
974            }
975            writer.write(lineEnding);
976        }
977    }
978
979    // copy from InputStream
980    //-----------------------------------------------------------------------
981    /**
982     * Copy bytes from an <code>InputStream</code> to an
983     * <code>OutputStream</code>.
984     * <p>
985     * This method buffers the input internally, so there is no need to use a
986     * <code>BufferedInputStream</code>.
987     * <p>
988     * Large streams (over 2GB) will return a bytes copied value of
989     * <code>-1</code> after the copy has completed since the correct
990     * number of bytes cannot be returned as an int. For large streams
991     * use the <code>copyLarge(InputStream, OutputStream)</code> method.
992     *
993     * @param input  the <code>InputStream</code> to read from
994     * @param output  the <code>OutputStream</code> to write to
995     * @return the number of bytes copied
996     * @throws NullPointerException if the input or output is null
997     * @throws IOException if an I/O error occurs
998     * @throws ArithmeticException if the byte count is too large
999     * @since Commons IO 1.1
1000     */
1001    public static int copy(InputStream input, OutputStream output) throws IOException {
1002        long count = copyLarge(input, output);
1003        if (count > Integer.MAX_VALUE) {
1004            return -1;
1005        }
1006        return (int) count;
1007    }
1008
1009    /**
1010     * Copy bytes from a large (over 2GB) <code>InputStream</code> to an
1011     * <code>OutputStream</code>.
1012     * <p>
1013     * This method buffers the input internally, so there is no need to use a
1014     * <code>BufferedInputStream</code>.
1015     *
1016     * @param input  the <code>InputStream</code> to read from
1017     * @param output  the <code>OutputStream</code> to write to
1018     * @return the number of bytes copied
1019     * @throws NullPointerException if the input or output is null
1020     * @throws IOException if an I/O error occurs
1021     * @since Commons IO 1.3
1022     */
1023    public static long copyLarge(InputStream input, OutputStream output)
1024            throws IOException {
1025        byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
1026        long count = 0;
1027        int n = 0;
1028        while (-1 != (n = input.read(buffer))) {
1029            output.write(buffer, 0, n);
1030            count += n;
1031        }
1032        return count;
1033    }
1034
1035    /**
1036     * Copy bytes from an <code>InputStream</code> to chars on a
1037     * <code>Writer</code> using the default character encoding of the platform.
1038     * <p>
1039     * This method buffers the input internally, so there is no need to use a
1040     * <code>BufferedInputStream</code>.
1041     * <p>
1042     * This method uses {@link InputStreamReader}.
1043     *
1044     * @param input  the <code>InputStream</code> to read from
1045     * @param output  the <code>Writer</code> to write to
1046     * @throws NullPointerException if the input or output is null
1047     * @throws IOException if an I/O error occurs
1048     * @since Commons IO 1.1
1049     */
1050    public static void copy(InputStream input, Writer output)
1051            throws IOException {
1052        InputStreamReader in = new InputStreamReader(input);
1053        copy(in, output);
1054    }
1055
1056    /**
1057     * Copy bytes from an <code>InputStream</code> to chars on a
1058     * <code>Writer</code> using the specified character encoding.
1059     * <p>
1060     * This method buffers the input internally, so there is no need to use a
1061     * <code>BufferedInputStream</code>.
1062     * <p>
1063     * Character encoding names can be found at
1064     * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
1065     * <p>
1066     * This method uses {@link InputStreamReader}.
1067     *
1068     * @param input  the <code>InputStream</code> to read from
1069     * @param output  the <code>Writer</code> to write to
1070     * @param encoding  the encoding to use, null means platform default
1071     * @throws NullPointerException if the input or output is null
1072     * @throws IOException if an I/O error occurs
1073     * @since Commons IO 1.1
1074     */
1075    public static void copy(InputStream input, Writer output, String encoding)
1076            throws IOException {
1077        if (encoding == null) {
1078            copy(input, output);
1079        } else {
1080            InputStreamReader in = new InputStreamReader(input, encoding);
1081            copy(in, output);
1082        }
1083    }
1084
1085    // copy from Reader
1086    //-----------------------------------------------------------------------
1087    /**
1088     * Copy chars from a <code>Reader</code> to a <code>Writer</code>.
1089     * <p>
1090     * This method buffers the input internally, so there is no need to use a
1091     * <code>BufferedReader</code>.
1092     * <p>
1093     * Large streams (over 2GB) will return a chars copied value of
1094     * <code>-1</code> after the copy has completed since the correct
1095     * number of chars cannot be returned as an int. For large streams
1096     * use the <code>copyLarge(Reader, Writer)</code> method.
1097     *
1098     * @param input  the <code>Reader</code> to read from
1099     * @param output  the <code>Writer</code> to write to
1100     * @return the number of characters copied
1101     * @throws NullPointerException if the input or output is null
1102     * @throws IOException if an I/O error occurs
1103     * @throws ArithmeticException if the character count is too large
1104     * @since Commons IO 1.1
1105     */
1106    public static int copy(Reader input, Writer output) throws IOException {
1107        long count = copyLarge(input, output);
1108        if (count > Integer.MAX_VALUE) {
1109            return -1;
1110        }
1111        return (int) count;
1112    }
1113
1114    /**
1115     * Copy chars from a large (over 2GB) <code>Reader</code> to a <code>Writer</code>.
1116     * <p>
1117     * This method buffers the input internally, so there is no need to use a
1118     * <code>BufferedReader</code>.
1119     *
1120     * @param input  the <code>Reader</code> to read from
1121     * @param output  the <code>Writer</code> to write to
1122     * @return the number of characters copied
1123     * @throws NullPointerException if the input or output is null
1124     * @throws IOException if an I/O error occurs
1125     * @since Commons IO 1.3
1126     */
1127    public static long copyLarge(Reader input, Writer output) throws IOException {
1128        char[] buffer = new char[DEFAULT_BUFFER_SIZE];
1129        long count = 0;
1130        int n = 0;
1131        while (-1 != (n = input.read(buffer))) {
1132            output.write(buffer, 0, n);
1133            count += n;
1134        }
1135        return count;
1136    }
1137
1138    /**
1139     * Copy chars from a <code>Reader</code> to bytes on an
1140     * <code>OutputStream</code> using the default character encoding of the
1141     * platform, and calling flush.
1142     * <p>
1143     * This method buffers the input internally, so there is no need to use a
1144     * <code>BufferedReader</code>.
1145     * <p>
1146     * Due to the implementation of OutputStreamWriter, this method performs a
1147     * flush.
1148     * <p>
1149     * This method uses {@link OutputStreamWriter}.
1150     *
1151     * @param input  the <code>Reader</code> to read from
1152     * @param output  the <code>OutputStream</code> to write to
1153     * @throws NullPointerException if the input or output is null
1154     * @throws IOException if an I/O error occurs
1155     * @since Commons IO 1.1
1156     */
1157    public static void copy(Reader input, OutputStream output)
1158            throws IOException {
1159        OutputStreamWriter out = new OutputStreamWriter(output);
1160        copy(input, out);
1161        // XXX Unless anyone is planning on rewriting OutputStreamWriter, we
1162        // have to flush here.
1163        out.flush();
1164    }
1165
1166    /**
1167     * Copy chars from a <code>Reader</code> to bytes on an
1168     * <code>OutputStream</code> using the specified character encoding, and
1169     * calling flush.
1170     * <p>
1171     * This method buffers the input internally, so there is no need to use a
1172     * <code>BufferedReader</code>.
1173     * <p>
1174     * Character encoding names can be found at
1175     * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
1176     * <p>
1177     * Due to the implementation of OutputStreamWriter, this method performs a
1178     * flush.
1179     * <p>
1180     * This method uses {@link OutputStreamWriter}.
1181     *
1182     * @param input  the <code>Reader</code> to read from
1183     * @param output  the <code>OutputStream</code> to write to
1184     * @param encoding  the encoding to use, null means platform default
1185     * @throws NullPointerException if the input or output is null
1186     * @throws IOException if an I/O error occurs
1187     * @since Commons IO 1.1
1188     */
1189    public static void copy(Reader input, OutputStream output, String encoding)
1190            throws IOException {
1191        if (encoding == null) {
1192            copy(input, output);
1193        } else {
1194            OutputStreamWriter out = new OutputStreamWriter(output, encoding);
1195            copy(input, out);
1196            // XXX Unless anyone is planning on rewriting OutputStreamWriter,
1197            // we have to flush here.
1198            out.flush();
1199        }
1200    }
1201
1202    // content equals
1203    //-----------------------------------------------------------------------
1204    /**
1205     * Compare the contents of two Streams to determine if they are equal or
1206     * not.
1207     * <p>
1208     * This method buffers the input internally using
1209     * <code>BufferedInputStream</code> if they are not already buffered.
1210     *
1211     * @param input1  the first stream
1212     * @param input2  the second stream
1213     * @return true if the content of the streams are equal or they both don't
1214     * exist, false otherwise
1215     * @throws NullPointerException if either input is null
1216     * @throws IOException if an I/O error occurs
1217     */
1218    public static boolean contentEquals(InputStream input1, InputStream input2)
1219            throws IOException {
1220        if (!(input1 instanceof BufferedInputStream)) {
1221            input1 = new BufferedInputStream(input1);
1222        }
1223        if (!(input2 instanceof BufferedInputStream)) {
1224            input2 = new BufferedInputStream(input2);
1225        }
1226
1227        int ch = input1.read();
1228        while (-1 != ch) {
1229            int ch2 = input2.read();
1230            if (ch != ch2) {
1231                return false;
1232            }
1233            ch = input1.read();
1234        }
1235
1236        int ch2 = input2.read();
1237        return (ch2 == -1);
1238    }
1239
1240    /**
1241     * Compare the contents of two Readers to determine if they are equal or
1242     * not.
1243     * <p>
1244     * This method buffers the input internally using
1245     * <code>BufferedReader</code> if they are not already buffered.
1246     *
1247     * @param input1  the first reader
1248     * @param input2  the second reader
1249     * @return true if the content of the readers are equal or they both don't
1250     * exist, false otherwise
1251     * @throws NullPointerException if either input is null
1252     * @throws IOException if an I/O error occurs
1253     * @since Commons IO 1.1
1254     */
1255    public static boolean contentEquals(Reader input1, Reader input2)
1256            throws IOException {
1257        if (!(input1 instanceof BufferedReader)) {
1258            input1 = new BufferedReader(input1);
1259        }
1260        if (!(input2 instanceof BufferedReader)) {
1261            input2 = new BufferedReader(input2);
1262        }
1263
1264        int ch = input1.read();
1265        while (-1 != ch) {
1266            int ch2 = input2.read();
1267            if (ch != ch2) {
1268                return false;
1269            }
1270            ch = input1.read();
1271        }
1272
1273        int ch2 = input2.read();
1274        return (ch2 == -1);
1275    }
1276
1277}
1278