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    public static byte[] toByteArray(String input) throws IOException {
277        return input.getBytes();
278    }
279
280    // read char[]
281    //-----------------------------------------------------------------------
282    /**
283     * Get the contents of an <code>InputStream</code> as a character array
284     * using the default character encoding of the platform.
285     * <p>
286     * This method buffers the input internally, so there is no need to use a
287     * <code>BufferedInputStream</code>.
288     *
289     * @param is  the <code>InputStream</code> to read from
290     * @return the requested character array
291     * @throws NullPointerException if the input is null
292     * @throws IOException if an I/O error occurs
293     * @since Commons IO 1.1
294     */
295    public static char[] toCharArray(InputStream is) throws IOException {
296        CharArrayWriter output = new CharArrayWriter();
297        copy(is, output);
298        return output.toCharArray();
299    }
300
301    /**
302     * Get the contents of an <code>InputStream</code> as a character array
303     * using the specified character encoding.
304     * <p>
305     * Character encoding names can be found at
306     * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
307     * <p>
308     * This method buffers the input internally, so there is no need to use a
309     * <code>BufferedInputStream</code>.
310     *
311     * @param is  the <code>InputStream</code> to read from
312     * @param encoding  the encoding to use, null means platform default
313     * @return the requested character array
314     * @throws NullPointerException if the input is null
315     * @throws IOException if an I/O error occurs
316     * @since Commons IO 1.1
317     */
318    public static char[] toCharArray(InputStream is, String encoding)
319            throws IOException {
320        CharArrayWriter output = new CharArrayWriter();
321        copy(is, output, encoding);
322        return output.toCharArray();
323    }
324
325    /**
326     * Get the contents of a <code>Reader</code> as a character array.
327     * <p>
328     * This method buffers the input internally, so there is no need to use a
329     * <code>BufferedReader</code>.
330     *
331     * @param input  the <code>Reader</code> to read from
332     * @return the requested character array
333     * @throws NullPointerException if the input is null
334     * @throws IOException if an I/O error occurs
335     * @since Commons IO 1.1
336     */
337    public static char[] toCharArray(Reader input) throws IOException {
338        CharArrayWriter sw = new CharArrayWriter();
339        copy(input, sw);
340        return sw.toCharArray();
341    }
342
343    // read toString
344    //-----------------------------------------------------------------------
345    /**
346     * Get the contents of an <code>InputStream</code> as a String
347     * using the default character encoding of the platform.
348     * <p>
349     * This method buffers the input internally, so there is no need to use a
350     * <code>BufferedInputStream</code>.
351     *
352     * @param input  the <code>InputStream</code> to read from
353     * @return the requested String
354     * @throws NullPointerException if the input is null
355     * @throws IOException if an I/O error occurs
356     */
357    public static String toString(InputStream input) throws IOException {
358        StringWriter sw = new StringWriter();
359        copy(input, sw);
360        return sw.toString();
361    }
362
363    /**
364     * Get the contents of an <code>InputStream</code> as a String
365     * using the specified character encoding.
366     * <p>
367     * Character encoding names can be found at
368     * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
369     * <p>
370     * This method buffers the input internally, so there is no need to use a
371     * <code>BufferedInputStream</code>.
372     *
373     * @param input  the <code>InputStream</code> to read from
374     * @param encoding  the encoding to use, null means platform default
375     * @return the requested String
376     * @throws NullPointerException if the input is null
377     * @throws IOException if an I/O error occurs
378     */
379    public static String toString(InputStream input, String encoding)
380            throws IOException {
381        StringWriter sw = new StringWriter();
382        copy(input, sw, encoding);
383        return sw.toString();
384    }
385
386    /**
387     * Get the contents of a <code>Reader</code> as a String.
388     * <p>
389     * This method buffers the input internally, so there is no need to use a
390     * <code>BufferedReader</code>.
391     *
392     * @param input  the <code>Reader</code> to read from
393     * @return the requested String
394     * @throws NullPointerException if the input is null
395     * @throws IOException if an I/O error occurs
396     */
397    public static String toString(Reader input) throws IOException {
398        StringWriter sw = new StringWriter();
399        copy(input, sw);
400        return sw.toString();
401    }
402
403    /**
404     * Get the contents of a <code>byte[]</code> as a String
405     * using the default character encoding of the platform.
406     *
407     * @param input the byte array to read from
408     * @return the requested String
409     * @throws NullPointerException if the input is null
410     * @throws IOException if an I/O error occurs (never occurs)
411     * @deprecated Use {@link String#String(byte[])}
412     */
413    public static String toString(byte[] input) throws IOException {
414        return new String(input);
415    }
416
417    /**
418     * Get the contents of a <code>byte[]</code> as a String
419     * using the specified character encoding.
420     * <p>
421     * Character encoding names can be found at
422     * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
423     *
424     * @param input the byte array to read from
425     * @param encoding  the encoding to use, null means platform default
426     * @return the requested String
427     * @throws NullPointerException if the input is null
428     * @throws IOException if an I/O error occurs (never occurs)
429     * @deprecated Use {@link String#String(byte[],String)}
430     */
431    public static String toString(byte[] input, String encoding)
432            throws IOException {
433        if (encoding == null) {
434            return new String(input);
435        } else {
436            return new String(input, encoding);
437        }
438    }
439
440    // readLines
441    //-----------------------------------------------------------------------
442    /**
443     * Get the contents of an <code>InputStream</code> as a list of Strings,
444     * one entry per line, using the default character encoding of the platform.
445     * <p>
446     * This method buffers the input internally, so there is no need to use a
447     * <code>BufferedInputStream</code>.
448     *
449     * @param input  the <code>InputStream</code> to read from, not null
450     * @return the list of Strings, never null
451     * @throws NullPointerException if the input is null
452     * @throws IOException if an I/O error occurs
453     * @since Commons IO 1.1
454     */
455    public static List<String> readLines(InputStream input) throws IOException {
456        InputStreamReader reader = new InputStreamReader(input);
457        return readLines(reader);
458    }
459
460    /**
461     * Get the contents of an <code>InputStream</code> as a list of Strings,
462     * one entry per line, using the specified character encoding.
463     * <p>
464     * Character encoding names can be found at
465     * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
466     * <p>
467     * This method buffers the input internally, so there is no need to use a
468     * <code>BufferedInputStream</code>.
469     *
470     * @param input  the <code>InputStream</code> to read from, not null
471     * @param encoding  the encoding to use, null means platform default
472     * @return the list of Strings, never null
473     * @throws NullPointerException if the input is null
474     * @throws IOException if an I/O error occurs
475     * @since Commons IO 1.1
476     */
477    public static List<String> readLines(InputStream input, String encoding) throws IOException {
478        if (encoding == null) {
479            return readLines(input);
480        } else {
481            InputStreamReader reader = new InputStreamReader(input, encoding);
482            return readLines(reader);
483        }
484    }
485
486    /**
487     * Get the contents of a <code>Reader</code> as a list of Strings,
488     * one entry per line.
489     * <p>
490     * This method buffers the input internally, so there is no need to use a
491     * <code>BufferedReader</code>.
492     *
493     * @param input  the <code>Reader</code> to read from, not null
494     * @return the list of Strings, never null
495     * @throws NullPointerException if the input is null
496     * @throws IOException if an I/O error occurs
497     * @since Commons IO 1.1
498     */
499    public static List<String> readLines(Reader input) throws IOException {
500        BufferedReader reader = new BufferedReader(input);
501        List<String> list = new ArrayList<String>();
502        String line = reader.readLine();
503        while (line != null) {
504            list.add(line);
505            line = reader.readLine();
506        }
507        return list;
508    }
509
510    // lineIterator
511    //-----------------------------------------------------------------------
512    /**
513     * Return an Iterator for the lines in a <code>Reader</code>.
514     * <p>
515     * <code>LineIterator</code> holds a reference to the open
516     * <code>Reader</code> specified here. When you have finished with the
517     * iterator you should close the reader to free internal resources.
518     * This can be done by closing the reader directly, or by calling
519     * {@link LineIterator#close()} or {@link LineIterator#closeQuietly(LineIterator)}.
520     * <p>
521     * The recommended usage pattern is:
522     * <pre>
523     * try {
524     *   LineIterator it = IOUtils.lineIterator(reader);
525     *   while (it.hasNext()) {
526     *     String line = it.nextLine();
527     *     /// do something with line
528     *   }
529     * } finally {
530     *   IOUtils.closeQuietly(reader);
531     * }
532     * </pre>
533     *
534     * @param reader  the <code>Reader</code> to read from, not null
535     * @return an Iterator of the lines in the reader, never null
536     * @throws IllegalArgumentException if the reader is null
537     * @since Commons IO 1.2
538     */
539    public static LineIterator lineIterator(Reader reader) {
540        return new LineIterator(reader);
541    }
542
543    /**
544     * Return an Iterator for the lines in an <code>InputStream</code>, using
545     * the character encoding specified (or default encoding if null).
546     * <p>
547     * <code>LineIterator</code> holds a reference to the open
548     * <code>InputStream</code> specified here. When you have finished with
549     * the iterator you should close the stream to free internal resources.
550     * This can be done by closing the stream directly, or by calling
551     * {@link LineIterator#close()} or {@link LineIterator#closeQuietly(LineIterator)}.
552     * <p>
553     * The recommended usage pattern is:
554     * <pre>
555     * try {
556     *   LineIterator it = IOUtils.lineIterator(stream, "UTF-8");
557     *   while (it.hasNext()) {
558     *     String line = it.nextLine();
559     *     /// do something with line
560     *   }
561     * } finally {
562     *   IOUtils.closeQuietly(stream);
563     * }
564     * </pre>
565     *
566     * @param input  the <code>InputStream</code> to read from, not null
567     * @param encoding  the encoding to use, null means platform default
568     * @return an Iterator of the lines in the reader, never null
569     * @throws IllegalArgumentException if the input is null
570     * @throws IOException if an I/O error occurs, such as if the encoding is invalid
571     * @since Commons IO 1.2
572     */
573    public static LineIterator lineIterator(InputStream input, String encoding)
574                     throws IOException {
575        Reader reader = null;
576        if (encoding == null) {
577            reader = new InputStreamReader(input);
578        } else {
579            reader = new InputStreamReader(input, encoding);
580        }
581        return new LineIterator(reader);
582    }
583
584    //-----------------------------------------------------------------------
585    /**
586     * Convert the specified string to an input stream, encoded as bytes
587     * using the default character encoding of the platform.
588     *
589     * @param input the string to convert
590     * @return an input stream
591     * @since Commons IO 1.1
592     */
593    public static InputStream toInputStream(String input) {
594        byte[] bytes = input.getBytes();
595        return new ByteArrayInputStream(bytes);
596    }
597
598    /**
599     * Convert the specified string to an input stream, encoded as bytes
600     * using the specified character encoding.
601     * <p>
602     * Character encoding names can be found at
603     * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
604     *
605     * @param input the string to convert
606     * @param encoding the encoding to use, null means platform default
607     * @throws IOException if the encoding is invalid
608     * @return an input stream
609     * @since Commons IO 1.1
610     */
611    public static InputStream toInputStream(String input, String encoding) throws IOException {
612        byte[] bytes = encoding != null ? input.getBytes(encoding) : input.getBytes();
613        return new ByteArrayInputStream(bytes);
614    }
615
616    // write byte[]
617    //-----------------------------------------------------------------------
618    /**
619     * Writes bytes from a <code>byte[]</code> to an <code>OutputStream</code>.
620     *
621     * @param data  the byte array to write, do not modify during output,
622     * null ignored
623     * @param output  the <code>OutputStream</code> to write to
624     * @throws NullPointerException if output is null
625     * @throws IOException if an I/O error occurs
626     * @since Commons IO 1.1
627     */
628    public static void write(byte[] data, OutputStream output)
629            throws IOException {
630        if (data != null) {
631            output.write(data);
632        }
633    }
634
635    /**
636     * Writes bytes from a <code>byte[]</code> to chars on a <code>Writer</code>
637     * using the default character encoding of the platform.
638     * <p>
639     * This method uses {@link String#String(byte[])}.
640     *
641     * @param data  the byte array to write, do not modify during output,
642     * null ignored
643     * @param output  the <code>Writer</code> to write to
644     * @throws NullPointerException if output is null
645     * @throws IOException if an I/O error occurs
646     * @since Commons IO 1.1
647     */
648    public static void write(byte[] data, Writer output) throws IOException {
649        if (data != null) {
650            output.write(new String(data));
651        }
652    }
653
654    /**
655     * Writes bytes from a <code>byte[]</code> to chars on a <code>Writer</code>
656     * using the specified character encoding.
657     * <p>
658     * Character encoding names can be found at
659     * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
660     * <p>
661     * This method uses {@link String#String(byte[], String)}.
662     *
663     * @param data  the byte array to write, do not modify during output,
664     * null ignored
665     * @param output  the <code>Writer</code> to write to
666     * @param encoding  the encoding to use, null means platform default
667     * @throws NullPointerException if output is null
668     * @throws IOException if an I/O error occurs
669     * @since Commons IO 1.1
670     */
671    public static void write(byte[] data, Writer output, String encoding)
672            throws IOException {
673        if (data != null) {
674            if (encoding == null) {
675                write(data, output);
676            } else {
677                output.write(new String(data, encoding));
678            }
679        }
680    }
681
682    // write char[]
683    //-----------------------------------------------------------------------
684    /**
685     * Writes chars from a <code>char[]</code> to a <code>Writer</code>
686     * using the default character encoding of the platform.
687     *
688     * @param data  the char array to write, do not modify during output,
689     * null ignored
690     * @param output  the <code>Writer</code> to write to
691     * @throws NullPointerException if output is null
692     * @throws IOException if an I/O error occurs
693     * @since Commons IO 1.1
694     */
695    public static void write(char[] data, Writer output) throws IOException {
696        if (data != null) {
697            output.write(data);
698        }
699    }
700
701    /**
702     * Writes chars from a <code>char[]</code> to bytes on an
703     * <code>OutputStream</code>.
704     * <p>
705     * This method uses {@link String#String(char[])} and
706     * {@link String#getBytes()}.
707     *
708     * @param data  the char array to write, do not modify during output,
709     * null ignored
710     * @param output  the <code>OutputStream</code> to write to
711     * @throws NullPointerException if output is null
712     * @throws IOException if an I/O error occurs
713     * @since Commons IO 1.1
714     */
715    public static void write(char[] data, OutputStream output)
716            throws IOException {
717        if (data != null) {
718            output.write(new String(data).getBytes());
719        }
720    }
721
722    /**
723     * Writes chars from a <code>char[]</code> to bytes on an
724     * <code>OutputStream</code> using the specified character encoding.
725     * <p>
726     * Character encoding names can be found at
727     * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
728     * <p>
729     * This method uses {@link String#String(char[])} and
730     * {@link String#getBytes(String)}.
731     *
732     * @param data  the char array to write, do not modify during output,
733     * null ignored
734     * @param output  the <code>OutputStream</code> to write to
735     * @param encoding  the encoding to use, null means platform default
736     * @throws NullPointerException if output is null
737     * @throws IOException if an I/O error occurs
738     * @since Commons IO 1.1
739     */
740    public static void write(char[] data, OutputStream output, String encoding)
741            throws IOException {
742        if (data != null) {
743            if (encoding == null) {
744                write(data, output);
745            } else {
746                output.write(new String(data).getBytes(encoding));
747            }
748        }
749    }
750
751    // write String
752    //-----------------------------------------------------------------------
753    /**
754     * Writes chars from a <code>String</code> to a <code>Writer</code>.
755     *
756     * @param data  the <code>String</code> to write, null ignored
757     * @param output  the <code>Writer</code> to write to
758     * @throws NullPointerException if output is null
759     * @throws IOException if an I/O error occurs
760     * @since Commons IO 1.1
761     */
762    public static void write(String data, Writer output) throws IOException {
763        if (data != null) {
764            output.write(data);
765        }
766    }
767
768    /**
769     * Writes chars from a <code>String</code> to bytes on an
770     * <code>OutputStream</code> using the default character encoding of the
771     * platform.
772     * <p>
773     * This method uses {@link String#getBytes()}.
774     *
775     * @param data  the <code>String</code> to write, null ignored
776     * @param output  the <code>OutputStream</code> to write to
777     * @throws NullPointerException if output is null
778     * @throws IOException if an I/O error occurs
779     * @since Commons IO 1.1
780     */
781    public static void write(String data, OutputStream output)
782            throws IOException {
783        if (data != null) {
784            output.write(data.getBytes());
785        }
786    }
787
788    /**
789     * Writes chars from a <code>String</code> to bytes on an
790     * <code>OutputStream</code> using the specified character encoding.
791     * <p>
792     * Character encoding names can be found at
793     * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
794     * <p>
795     * This method uses {@link String#getBytes(String)}.
796     *
797     * @param data  the <code>String</code> to write, null ignored
798     * @param output  the <code>OutputStream</code> to write to
799     * @param encoding  the encoding to use, null means platform default
800     * @throws NullPointerException if output is null
801     * @throws IOException if an I/O error occurs
802     * @since Commons IO 1.1
803     */
804    public static void write(String data, OutputStream output, String encoding)
805            throws IOException {
806        if (data != null) {
807            if (encoding == null) {
808                write(data, output);
809            } else {
810                output.write(data.getBytes(encoding));
811            }
812        }
813    }
814
815    // write StringBuffer
816    //-----------------------------------------------------------------------
817    /**
818     * Writes chars from a <code>StringBuffer</code> to a <code>Writer</code>.
819     *
820     * @param data  the <code>StringBuffer</code> to write, null ignored
821     * @param output  the <code>Writer</code> to write to
822     * @throws NullPointerException if output is null
823     * @throws IOException if an I/O error occurs
824     * @since Commons IO 1.1
825     */
826    public static void write(StringBuffer data, Writer output)
827            throws IOException {
828        if (data != null) {
829            output.write(data.toString());
830        }
831    }
832
833    /**
834     * Writes chars from a <code>StringBuffer</code> to bytes on an
835     * <code>OutputStream</code> using the default character encoding of the
836     * platform.
837     * <p>
838     * This method uses {@link String#getBytes()}.
839     *
840     * @param data  the <code>StringBuffer</code> to write, null ignored
841     * @param output  the <code>OutputStream</code> to write to
842     * @throws NullPointerException if output is null
843     * @throws IOException if an I/O error occurs
844     * @since Commons IO 1.1
845     */
846    public static void write(StringBuffer data, OutputStream output)
847            throws IOException {
848        if (data != null) {
849            output.write(data.toString().getBytes());
850        }
851    }
852
853    /**
854     * Writes chars from a <code>StringBuffer</code> to bytes on an
855     * <code>OutputStream</code> using the specified character encoding.
856     * <p>
857     * Character encoding names can be found at
858     * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
859     * <p>
860     * This method uses {@link String#getBytes(String)}.
861     *
862     * @param data  the <code>StringBuffer</code> to write, null ignored
863     * @param output  the <code>OutputStream</code> to write to
864     * @param encoding  the encoding to use, null means platform default
865     * @throws NullPointerException if output is null
866     * @throws IOException if an I/O error occurs
867     * @since Commons IO 1.1
868     */
869    public static void write(StringBuffer data, OutputStream output,
870            String encoding) throws IOException {
871        if (data != null) {
872            if (encoding == null) {
873                write(data, output);
874            } else {
875                output.write(data.toString().getBytes(encoding));
876            }
877        }
878    }
879
880    // writeLines
881    //-----------------------------------------------------------------------
882    /**
883     * Writes the <code>toString()</code> value of each item in a collection to
884     * an <code>OutputStream</code> line by line, using the default character
885     * encoding of the platform and the specified line ending.
886     *
887     * @param lines  the lines to write, null entries produce blank lines
888     * @param lineEnding  the line separator to use, null is system default
889     * @param output  the <code>OutputStream</code> to write to, not null, not closed
890     * @throws NullPointerException if the output is null
891     * @throws IOException if an I/O error occurs
892     * @since Commons IO 1.1
893     */
894    public static void writeLines(Collection<Object> lines, String lineEnding,
895            OutputStream output) throws IOException {
896        if (lines == null) {
897            return;
898        }
899        if (lineEnding == null) {
900            lineEnding = LINE_SEPARATOR;
901        }
902        for (Iterator<Object> it = lines.iterator(); it.hasNext(); ) {
903            Object line = it.next();
904            if (line != null) {
905                output.write(line.toString().getBytes());
906            }
907            output.write(lineEnding.getBytes());
908        }
909    }
910
911    /**
912     * Writes the <code>toString()</code> value of each item in a collection to
913     * an <code>OutputStream</code> line by line, using the specified character
914     * encoding and the specified line ending.
915     * <p>
916     * Character encoding names can be found at
917     * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
918     *
919     * @param lines  the lines to write, null entries produce blank lines
920     * @param lineEnding  the line separator to use, null is system default
921     * @param output  the <code>OutputStream</code> to write to, not null, not closed
922     * @param encoding  the encoding to use, null means platform default
923     * @throws NullPointerException if the output is null
924     * @throws IOException if an I/O error occurs
925     * @since Commons IO 1.1
926     */
927    public static void writeLines(Collection<Object> lines, String lineEnding,
928            OutputStream output, String encoding) throws IOException {
929        if (encoding == null) {
930            writeLines(lines, lineEnding, output);
931        } else {
932            if (lines == null) {
933                return;
934            }
935            if (lineEnding == null) {
936                lineEnding = LINE_SEPARATOR;
937            }
938            for (Iterator<Object> it = lines.iterator(); it.hasNext(); ) {
939                Object line = it.next();
940                if (line != null) {
941                    output.write(line.toString().getBytes(encoding));
942                }
943                output.write(lineEnding.getBytes(encoding));
944            }
945        }
946    }
947
948    /**
949     * Writes the <code>toString()</code> value of each item in a collection to
950     * a <code>Writer</code> line by line, using the specified line ending.
951     *
952     * @param lines  the lines to write, null entries produce blank lines
953     * @param lineEnding  the line separator to use, null is system default
954     * @param writer  the <code>Writer</code> to write to, not null, not closed
955     * @throws NullPointerException if the input is null
956     * @throws IOException if an I/O error occurs
957     * @since Commons IO 1.1
958     */
959    public static void writeLines(Collection<Object> lines, String lineEnding,
960            Writer writer) throws IOException {
961        if (lines == null) {
962            return;
963        }
964        if (lineEnding == null) {
965            lineEnding = LINE_SEPARATOR;
966        }
967        for (Iterator<Object> it = lines.iterator(); it.hasNext(); ) {
968            Object line = it.next();
969            if (line != null) {
970                writer.write(line.toString());
971            }
972            writer.write(lineEnding);
973        }
974    }
975
976    // copy from InputStream
977    //-----------------------------------------------------------------------
978    /**
979     * Copy bytes from an <code>InputStream</code> to an
980     * <code>OutputStream</code>.
981     * <p>
982     * This method buffers the input internally, so there is no need to use a
983     * <code>BufferedInputStream</code>.
984     * <p>
985     * Large streams (over 2GB) will return a bytes copied value of
986     * <code>-1</code> after the copy has completed since the correct
987     * number of bytes cannot be returned as an int. For large streams
988     * use the <code>copyLarge(InputStream, OutputStream)</code> method.
989     *
990     * @param input  the <code>InputStream</code> to read from
991     * @param output  the <code>OutputStream</code> to write to
992     * @return the number of bytes copied
993     * @throws NullPointerException if the input or output is null
994     * @throws IOException if an I/O error occurs
995     * @throws ArithmeticException if the byte count is too large
996     * @since Commons IO 1.1
997     */
998    public static int copy(InputStream input, OutputStream output) throws IOException {
999        long count = copyLarge(input, output);
1000        if (count > Integer.MAX_VALUE) {
1001            return -1;
1002        }
1003        return (int) count;
1004    }
1005
1006    /**
1007     * Copy bytes from a large (over 2GB) <code>InputStream</code> to an
1008     * <code>OutputStream</code>.
1009     * <p>
1010     * This method buffers the input internally, so there is no need to use a
1011     * <code>BufferedInputStream</code>.
1012     *
1013     * @param input  the <code>InputStream</code> to read from
1014     * @param output  the <code>OutputStream</code> to write to
1015     * @return the number of bytes copied
1016     * @throws NullPointerException if the input or output is null
1017     * @throws IOException if an I/O error occurs
1018     * @since Commons IO 1.3
1019     */
1020    public static long copyLarge(InputStream input, OutputStream output)
1021            throws IOException {
1022        byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
1023        long count = 0;
1024        int n = 0;
1025        while (-1 != (n = input.read(buffer))) {
1026            output.write(buffer, 0, n);
1027            count += n;
1028        }
1029        return count;
1030    }
1031
1032    /**
1033     * Copy bytes from an <code>InputStream</code> to chars on a
1034     * <code>Writer</code> using the default character encoding of the platform.
1035     * <p>
1036     * This method buffers the input internally, so there is no need to use a
1037     * <code>BufferedInputStream</code>.
1038     * <p>
1039     * This method uses {@link InputStreamReader}.
1040     *
1041     * @param input  the <code>InputStream</code> to read from
1042     * @param output  the <code>Writer</code> to write to
1043     * @throws NullPointerException if the input or output is null
1044     * @throws IOException if an I/O error occurs
1045     * @since Commons IO 1.1
1046     */
1047    public static void copy(InputStream input, Writer output)
1048            throws IOException {
1049        InputStreamReader in = new InputStreamReader(input);
1050        copy(in, output);
1051    }
1052
1053    /**
1054     * Copy bytes from an <code>InputStream</code> to chars on a
1055     * <code>Writer</code> using the specified character encoding.
1056     * <p>
1057     * This method buffers the input internally, so there is no need to use a
1058     * <code>BufferedInputStream</code>.
1059     * <p>
1060     * Character encoding names can be found at
1061     * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
1062     * <p>
1063     * This method uses {@link InputStreamReader}.
1064     *
1065     * @param input  the <code>InputStream</code> to read from
1066     * @param output  the <code>Writer</code> to write to
1067     * @param encoding  the encoding to use, null means platform default
1068     * @throws NullPointerException if the input or output is null
1069     * @throws IOException if an I/O error occurs
1070     * @since Commons IO 1.1
1071     */
1072    public static void copy(InputStream input, Writer output, String encoding)
1073            throws IOException {
1074        if (encoding == null) {
1075            copy(input, output);
1076        } else {
1077            InputStreamReader in = new InputStreamReader(input, encoding);
1078            copy(in, output);
1079        }
1080    }
1081
1082    // copy from Reader
1083    //-----------------------------------------------------------------------
1084    /**
1085     * Copy chars from a <code>Reader</code> to a <code>Writer</code>.
1086     * <p>
1087     * This method buffers the input internally, so there is no need to use a
1088     * <code>BufferedReader</code>.
1089     * <p>
1090     * Large streams (over 2GB) will return a chars copied value of
1091     * <code>-1</code> after the copy has completed since the correct
1092     * number of chars cannot be returned as an int. For large streams
1093     * use the <code>copyLarge(Reader, Writer)</code> method.
1094     *
1095     * @param input  the <code>Reader</code> to read from
1096     * @param output  the <code>Writer</code> to write to
1097     * @return the number of characters copied
1098     * @throws NullPointerException if the input or output is null
1099     * @throws IOException if an I/O error occurs
1100     * @throws ArithmeticException if the character count is too large
1101     * @since Commons IO 1.1
1102     */
1103    public static int copy(Reader input, Writer output) throws IOException {
1104        long count = copyLarge(input, output);
1105        if (count > Integer.MAX_VALUE) {
1106            return -1;
1107        }
1108        return (int) count;
1109    }
1110
1111    /**
1112     * Copy chars from a large (over 2GB) <code>Reader</code> to a <code>Writer</code>.
1113     * <p>
1114     * This method buffers the input internally, so there is no need to use a
1115     * <code>BufferedReader</code>.
1116     *
1117     * @param input  the <code>Reader</code> to read from
1118     * @param output  the <code>Writer</code> to write to
1119     * @return the number of characters copied
1120     * @throws NullPointerException if the input or output is null
1121     * @throws IOException if an I/O error occurs
1122     * @since Commons IO 1.3
1123     */
1124    public static long copyLarge(Reader input, Writer output) throws IOException {
1125        char[] buffer = new char[DEFAULT_BUFFER_SIZE];
1126        long count = 0;
1127        int n = 0;
1128        while (-1 != (n = input.read(buffer))) {
1129            output.write(buffer, 0, n);
1130            count += n;
1131        }
1132        return count;
1133    }
1134
1135    /**
1136     * Copy chars from a <code>Reader</code> to bytes on an
1137     * <code>OutputStream</code> using the default character encoding of the
1138     * platform, and calling flush.
1139     * <p>
1140     * This method buffers the input internally, so there is no need to use a
1141     * <code>BufferedReader</code>.
1142     * <p>
1143     * Due to the implementation of OutputStreamWriter, this method performs a
1144     * flush.
1145     * <p>
1146     * This method uses {@link OutputStreamWriter}.
1147     *
1148     * @param input  the <code>Reader</code> to read from
1149     * @param output  the <code>OutputStream</code> to write to
1150     * @throws NullPointerException if the input or output is null
1151     * @throws IOException if an I/O error occurs
1152     * @since Commons IO 1.1
1153     */
1154    public static void copy(Reader input, OutputStream output)
1155            throws IOException {
1156        OutputStreamWriter out = new OutputStreamWriter(output);
1157        copy(input, out);
1158        // XXX Unless anyone is planning on rewriting OutputStreamWriter, we
1159        // have to flush here.
1160        out.flush();
1161    }
1162
1163    /**
1164     * Copy chars from a <code>Reader</code> to bytes on an
1165     * <code>OutputStream</code> using the specified character encoding, and
1166     * calling flush.
1167     * <p>
1168     * This method buffers the input internally, so there is no need to use a
1169     * <code>BufferedReader</code>.
1170     * <p>
1171     * Character encoding names can be found at
1172     * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
1173     * <p>
1174     * Due to the implementation of OutputStreamWriter, this method performs a
1175     * flush.
1176     * <p>
1177     * This method uses {@link OutputStreamWriter}.
1178     *
1179     * @param input  the <code>Reader</code> to read from
1180     * @param output  the <code>OutputStream</code> to write to
1181     * @param encoding  the encoding to use, null means platform default
1182     * @throws NullPointerException if the input or output is null
1183     * @throws IOException if an I/O error occurs
1184     * @since Commons IO 1.1
1185     */
1186    public static void copy(Reader input, OutputStream output, String encoding)
1187            throws IOException {
1188        if (encoding == null) {
1189            copy(input, output);
1190        } else {
1191            OutputStreamWriter out = new OutputStreamWriter(output, encoding);
1192            copy(input, out);
1193            // XXX Unless anyone is planning on rewriting OutputStreamWriter,
1194            // we have to flush here.
1195            out.flush();
1196        }
1197    }
1198
1199    // content equals
1200    //-----------------------------------------------------------------------
1201    /**
1202     * Compare the contents of two Streams to determine if they are equal or
1203     * not.
1204     * <p>
1205     * This method buffers the input internally using
1206     * <code>BufferedInputStream</code> if they are not already buffered.
1207     *
1208     * @param input1  the first stream
1209     * @param input2  the second stream
1210     * @return true if the content of the streams are equal or they both don't
1211     * exist, false otherwise
1212     * @throws NullPointerException if either input is null
1213     * @throws IOException if an I/O error occurs
1214     */
1215    public static boolean contentEquals(InputStream input1, InputStream input2)
1216            throws IOException {
1217        if (!(input1 instanceof BufferedInputStream)) {
1218            input1 = new BufferedInputStream(input1);
1219        }
1220        if (!(input2 instanceof BufferedInputStream)) {
1221            input2 = new BufferedInputStream(input2);
1222        }
1223
1224        int ch = input1.read();
1225        while (-1 != ch) {
1226            int ch2 = input2.read();
1227            if (ch != ch2) {
1228                return false;
1229            }
1230            ch = input1.read();
1231        }
1232
1233        int ch2 = input2.read();
1234        return (ch2 == -1);
1235    }
1236
1237    /**
1238     * Compare the contents of two Readers to determine if they are equal or
1239     * not.
1240     * <p>
1241     * This method buffers the input internally using
1242     * <code>BufferedReader</code> if they are not already buffered.
1243     *
1244     * @param input1  the first reader
1245     * @param input2  the second reader
1246     * @return true if the content of the readers are equal or they both don't
1247     * exist, false otherwise
1248     * @throws NullPointerException if either input is null
1249     * @throws IOException if an I/O error occurs
1250     * @since Commons IO 1.1
1251     */
1252    public static boolean contentEquals(Reader input1, Reader input2)
1253            throws IOException {
1254        if (!(input1 instanceof BufferedReader)) {
1255            input1 = new BufferedReader(input1);
1256        }
1257        if (!(input2 instanceof BufferedReader)) {
1258            input2 = new BufferedReader(input2);
1259        }
1260
1261        int ch = input1.read();
1262        while (-1 != ch) {
1263            int ch2 = input2.read();
1264            if (ch != ch2) {
1265                return false;
1266            }
1267            ch = input1.read();
1268        }
1269
1270        int ch2 = input2.read();
1271        return (ch2 == -1);
1272    }
1273
1274}
1275