1bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor/*
21d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Copyright (C) 2007 The Guava Authors
3bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor *
4bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * Licensed under the Apache License, Version 2.0 (the "License");
5bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * you may not use this file except in compliance with the License.
6bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * You may obtain a copy of the License at
7bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor *
8bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * http://www.apache.org/licenses/LICENSE-2.0
9bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor *
10bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * Unless required by applicable law or agreed to in writing, software
11bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * distributed under the License is distributed on an "AS IS" BASIS,
12bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * See the License for the specific language governing permissions and
14bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * limitations under the License.
15bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor */
16bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
17bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorpackage com.google.common.io;
18bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.annotations.Beta;
20bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorimport com.google.common.base.Preconditions;
21bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
22bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorimport java.io.Closeable;
23bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorimport java.io.EOFException;
24bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorimport java.io.IOException;
25bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorimport java.io.InputStream;
26bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorimport java.io.InputStreamReader;
27bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorimport java.io.OutputStream;
28bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorimport java.io.OutputStreamWriter;
29bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorimport java.io.Reader;
30bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorimport java.io.StringReader;
31bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorimport java.io.Writer;
32bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorimport java.nio.CharBuffer;
33bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorimport java.nio.charset.Charset;
34bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorimport java.util.ArrayList;
35bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorimport java.util.Arrays;
36bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorimport java.util.List;
37bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
38bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor/**
39bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * Provides utility methods for working with character streams.
40bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor *
41bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * <p>All method parameters must be non-null unless documented otherwise.
42bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor *
43bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * <p>Some of the methods in this class take arguments with a generic type of
44bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * {@code Readable & Closeable}. A {@link java.io.Reader} implements both of
45bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * those interfaces. Similarly for {@code Appendable & Closeable} and
46bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * {@link java.io.Writer}.
47bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor *
48bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * @author Chris Nokleberg
49bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * @author Bin Zhu
501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @since 1.0
51bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor */
521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert@Beta
53bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorpublic final class CharStreams {
54bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  private static final int BUF_SIZE = 0x800; // 2K chars (4K bytes)
55bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
56bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  private CharStreams() {}
57bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
58bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  /**
59bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * Returns a factory that will supply instances of {@link StringReader} that
60bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * read a string value.
61bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   *
62bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param value the string to read
63bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @return the factory
64bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   */
651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public static InputSupplier<StringReader> newReaderSupplier(
661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      final String value) {
67bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    Preconditions.checkNotNull(value);
68bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    return new InputSupplier<StringReader>() {
691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override
70bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      public StringReader getInput() {
71bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor        return new StringReader(value);
72bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      }
73bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    };
74bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  }
75bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
76bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  /**
77bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * Returns a factory that will supply instances of {@link InputStreamReader},
78bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * using the given {@link InputStream} factory and character set.
79bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   *
80bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param in the factory that will be used to open input streams
81bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param charset the character set used to decode the input stream
82bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @return the factory
83bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   */
84bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  public static InputSupplier<InputStreamReader> newReaderSupplier(
85bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      final InputSupplier<? extends InputStream> in, final Charset charset) {
86bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    Preconditions.checkNotNull(in);
87bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    Preconditions.checkNotNull(charset);
88bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    return new InputSupplier<InputStreamReader>() {
891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override
90bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      public InputStreamReader getInput() throws IOException {
91bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor        return new InputStreamReader(in.getInput(), charset);
92bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      }
93bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    };
94bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  }
95bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
96bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  /**
97bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * Returns a factory that will supply instances of {@link OutputStreamWriter},
98bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * using the given {@link OutputStream} factory and character set.
99bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   *
100bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param out the factory that will be used to open output streams
101bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param charset the character set used to encode the output stream
102bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @return the factory
103bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   */
104bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  public static OutputSupplier<OutputStreamWriter> newWriterSupplier(
105bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      final OutputSupplier<? extends OutputStream> out, final Charset charset) {
106bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    Preconditions.checkNotNull(out);
107bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    Preconditions.checkNotNull(charset);
108bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    return new OutputSupplier<OutputStreamWriter>() {
1091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override
110bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      public OutputStreamWriter getOutput() throws IOException {
111bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor        return new OutputStreamWriter(out.getOutput(), charset);
112bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      }
113bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    };
114bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  }
115bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
116bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  /**
117bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * Writes a character sequence (such as a string) to an appendable
118bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * object from the given supplier.
119bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   *
120bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param from the character sequence to write
121bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param to the output supplier
122bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @throws IOException if an I/O error occurs
123bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   */
124bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  public static <W extends Appendable & Closeable> void write(CharSequence from,
125bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      OutputSupplier<W> to) throws IOException {
126bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    Preconditions.checkNotNull(from);
127bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    boolean threw = true;
128bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    W out = to.getOutput();
129bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    try {
130bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      out.append(from);
131bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      threw = false;
132bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    } finally {
133bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      Closeables.close(out, threw);
134bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    }
135bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  }
136bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
137bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  /**
138bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * Opens {@link Readable} and {@link Appendable} objects from the
139bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * given factories, copies all characters between the two, and closes
140bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * them.
141bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   *
142bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param from the input factory
143bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param to the output factory
144bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @return the number of characters copied
145bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @throws IOException if an I/O error occurs
146bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   */
147bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  public static <R extends Readable & Closeable,
148bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      W extends Appendable & Closeable> long copy(InputSupplier<R> from,
149bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      OutputSupplier<W> to) throws IOException {
1501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int successfulOps = 0;
151bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    R in = from.getInput();
152bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    try {
153bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      W out = to.getOutput();
154bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      try {
155bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor        long count = copy(in, out);
1561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        successfulOps++;
157bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor        return count;
158bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      } finally {
1591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Closeables.close(out, successfulOps < 1);
1601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        successfulOps++;
161bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      }
162bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    } finally {
1631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Closeables.close(in, successfulOps < 2);
164bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    }
165bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  }
166bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
167bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  /**
168bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * Opens a {@link Readable} object from the supplier, copies all characters
169bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * to the {@link Appendable} object, and closes the input. Does not close
170bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * or flush the output.
171bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   *
172bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param from the input factory
173bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param to the object to write to
174bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @return the number of characters copied
175bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @throws IOException if an I/O error occurs
176bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   */
1771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public static <R extends Readable & Closeable> long copy(
1781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      InputSupplier<R> from, Appendable to) throws IOException {
179bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    boolean threw = true;
180bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    R in = from.getInput();
181bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    try {
182bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      long count = copy(in, to);
183bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      threw = false;
184bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      return count;
185bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    } finally {
186bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      Closeables.close(in, threw);
187bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    }
188bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  }
189bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
190bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  /**
191bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * Copies all characters between the {@link Readable} and {@link Appendable}
192bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * objects. Does not close or flush either object.
193bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   *
194bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param from the object to read from
195bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param to the object to write to
196bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @return the number of characters copied
197bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @throws IOException if an I/O error occurs
198bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   */
199bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  public static long copy(Readable from, Appendable to) throws IOException {
200bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    CharBuffer buf = CharBuffer.allocate(BUF_SIZE);
201bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    long total = 0;
202bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    while (true) {
203bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      int r = from.read(buf);
204bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      if (r == -1) {
205bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor        break;
206bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      }
207bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      buf.flip();
208bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      to.append(buf, 0, r);
209bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      total += r;
210bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    }
211bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    return total;
212bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  }
213bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
214bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  /**
215bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * Reads all characters from a {@link Readable} object into a {@link String}.
216bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * Does not close the {@code Readable}.
217bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   *
218bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param r the object to read from
219bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @return a string containing all the characters
220bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @throws IOException if an I/O error occurs
221bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   */
222bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  public static String toString(Readable r) throws IOException {
223bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    return toStringBuilder(r).toString();
224bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  }
225bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
226bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  /**
227bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * Returns the characters from a {@link Readable} & {@link Closeable} object
228bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * supplied by a factory as a {@link String}.
229bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   *
230bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param supplier the factory to read from
231bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @return a string containing all the characters
232bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @throws IOException if an I/O error occurs
233bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   */
234bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  public static <R extends Readable & Closeable> String toString(
235bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      InputSupplier<R> supplier) throws IOException {
236bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    return toStringBuilder(supplier).toString();
237bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  }
238bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
239bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  /**
240bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * Reads all characters from a {@link Readable} object into a new
241bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * {@link StringBuilder} instance. Does not close the {@code Readable}.
242bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   *
243bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param r the object to read from
244bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @return a {@link StringBuilder} containing all the characters
245bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @throws IOException if an I/O error occurs
246bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   */
247bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  private static StringBuilder toStringBuilder(Readable r) throws IOException {
248bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    StringBuilder sb = new StringBuilder();
249bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    copy(r, sb);
250bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    return sb;
251bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  }
252bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
253bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  /**
254bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * Returns the characters from a {@link Readable} & {@link Closeable} object
255bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * supplied by a factory as a new {@link StringBuilder} instance.
256bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   *
257bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param supplier the factory to read from
258bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @throws IOException if an I/O error occurs
259bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   */
260bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  private static <R extends Readable & Closeable> StringBuilder toStringBuilder(
261bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      InputSupplier<R> supplier) throws IOException {
262bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    boolean threw = true;
263bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    R r = supplier.getInput();
264bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    try {
265bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      StringBuilder result = toStringBuilder(r);
266bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      threw = false;
267bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      return result;
268bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    } finally {
269bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      Closeables.close(r, threw);
270bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    }
271bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  }
272bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
273bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  /**
274bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * Reads the first line from a {@link Readable} & {@link Closeable} object
275bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * supplied by a factory. The line does not include line-termination
276bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * characters, but does include other leading and trailing whitespace.
277bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   *
278bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param supplier the factory to read from
279bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @return the first line, or null if the reader is empty
280bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @throws IOException if an I/O error occurs
281bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   */
282bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  public static <R extends Readable & Closeable> String readFirstLine(
283bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      InputSupplier<R> supplier) throws IOException {
284bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    boolean threw = true;
285bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    R r = supplier.getInput();
286bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    try {
287bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      String line = new LineReader(r).readLine();
288bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      threw = false;
289bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      return line;
290bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    } finally {
291bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      Closeables.close(r, threw);
292bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    }
293bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  }
294bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
295bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  /**
296bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * Reads all of the lines from a {@link Readable} & {@link Closeable} object
297bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * supplied by a factory. The lines do not include line-termination
298bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * characters, but do include other leading and trailing whitespace.
299bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   *
300bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param supplier the factory to read from
301bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @return a mutable {@link List} containing all the lines
302bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @throws IOException if an I/O error occurs
303bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   */
304bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  public static <R extends Readable & Closeable> List<String> readLines(
305bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      InputSupplier<R> supplier) throws IOException {
306bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    boolean threw = true;
307bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    R r = supplier.getInput();
308bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    try {
309bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      List<String> result = readLines(r);
310bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      threw = false;
311bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      return result;
312bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    } finally {
313bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      Closeables.close(r, threw);
314bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    }
315bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  }
316bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
317bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  /**
318bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * Reads all of the lines from a {@link Readable} object. The lines do
319bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * not include line-termination characters, but do include other
320bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * leading and trailing whitespace.
321bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   *
322bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * <p>Does not close the {@code Readable}. If reading files or resources you
323bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * should use the {@link Files#readLines} and {@link Resources#readLines}
324bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * methods.
325bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   *
326bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param r the object to read from
327bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @return a mutable {@link List} containing all the lines
328bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @throws IOException if an I/O error occurs
329bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   */
330bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  public static List<String> readLines(Readable r) throws IOException {
331bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    List<String> result = new ArrayList<String>();
332bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    LineReader lineReader = new LineReader(r);
333bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    String line;
334bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    while ((line = lineReader.readLine()) != null) {
335bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      result.add(line);
336bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    }
337bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    return result;
338bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  }
339bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
340bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  /**
341bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * Streams lines from a {@link Readable} and {@link Closeable} object
342bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * supplied by a factory, stopping when our callback returns false, or we
343bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * have read all of the lines.
344bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   *
345bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param supplier the factory to read from
346bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param callback the LineProcessor to use to handle the lines
347bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @return the output of processing the lines
348bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @throws IOException if an I/O error occurs
349bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   */
350bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  public static <R extends Readable & Closeable, T> T readLines(
351bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      InputSupplier<R> supplier, LineProcessor<T> callback) throws IOException {
352bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    boolean threw = true;
353bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    R r = supplier.getInput();
354bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    try {
355bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      LineReader lineReader = new LineReader(r);
356bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      String line;
357bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      while ((line = lineReader.readLine()) != null) {
358bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor        if (!callback.processLine(line)) {
359bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor          break;
360bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor        }
361bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      }
362bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      threw = false;
363bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    } finally {
364bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      Closeables.close(r, threw);
365bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    }
366bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    return callback.getResult();
367bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  }
368bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
369bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  /**
370bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * Joins multiple {@link Reader} suppliers into a single supplier.
371bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * Reader returned from the supplier will contain the concatenated data
372bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * from the readers of the underlying suppliers.
373bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   *
374bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * <p>Reading from the joined reader will throw a {@link NullPointerException}
375bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * if any of the suppliers are null or return null.
376bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   *
377bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * <p>Only one underlying reader will be open at a time. Closing the
378bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * joined reader will close the open underlying reader.
379bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   *
380bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param suppliers the suppliers to concatenate
381bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @return a supplier that will return a reader containing the concatenated
382bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   *     data
383bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   */
384bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  public static InputSupplier<Reader> join(
385bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      final Iterable<? extends InputSupplier<? extends Reader>> suppliers) {
386bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    return new InputSupplier<Reader>() {
3871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override public Reader getInput() throws IOException {
388bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor        return new MultiReader(suppliers.iterator());
389bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      }
390bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    };
391bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  }
392bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
393bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  /** Varargs form of {@link #join(Iterable)}. */
394bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  public static InputSupplier<Reader> join(
395bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      InputSupplier<? extends Reader>... suppliers) {
396bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    return join(Arrays.asList(suppliers));
397bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  }
398bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
399bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  /**
400bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * Discards {@code n} characters of data from the reader. This method
401bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * will block until the full amount has been skipped. Does not close the
402bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * reader.
403bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   *
404bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param reader the reader to read from
405bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param n the number of characters to skip
406bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @throws EOFException if this stream reaches the end before skipping all
407bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   *     the bytes
408bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @throws IOException if an I/O error occurs
409bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   */
410bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  public static void skipFully(Reader reader, long n) throws IOException {
411bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    while (n > 0) {
412bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      long amt = reader.skip(n);
413bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      if (amt == 0) {
414bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor        // force a blocking read
415bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor        if (reader.read() == -1) {
416bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor          throw new EOFException();
417bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor        }
418bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor        n--;
419bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      } else {
420bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor        n -= amt;
421bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      }
422bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    }
423bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  }
424bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
425bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  /**
426bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * Returns a Writer that sends all output to the given {@link Appendable}
427bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * target. Closing the writer will close the target if it is {@link
428bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * Closeable}, and flushing the writer will flush the target if it is {@link
429bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * java.io.Flushable}.
430bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   *
431bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @param target the object to which output will be sent
432bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   * @return a new Writer object, unless target is a Writer, in which case the
433bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   *     target is returned
434bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor   */
435bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  public static Writer asWriter(Appendable target) {
436bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    if (target instanceof Writer) {
437bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      return (Writer) target;
438bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    }
439bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    return new AppendableWriter(target);
440bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  }
441bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor}
442