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