001/*
002 * Copyright (C) 2007 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package com.google.common.io;
018
019import static com.google.common.base.Preconditions.checkNotNull;
020import static com.google.common.base.Preconditions.checkPositionIndexes;
021
022import com.google.common.annotations.Beta;
023import com.google.common.base.Charsets;
024import com.google.common.base.Function;
025import com.google.common.collect.Iterables;
026
027import java.io.Closeable;
028import java.io.EOFException;
029import java.io.IOException;
030import java.io.InputStream;
031import java.io.InputStreamReader;
032import java.io.OutputStream;
033import java.io.OutputStreamWriter;
034import java.io.Reader;
035import java.io.StringReader;
036import java.io.Writer;
037import java.nio.CharBuffer;
038import java.nio.charset.Charset;
039import java.util.ArrayList;
040import java.util.Arrays;
041import java.util.List;
042
043/**
044 * Provides utility methods for working with character streams.
045 *
046 * <p>All method parameters must be non-null unless documented otherwise.
047 *
048 * <p>Some of the methods in this class take arguments with a generic type of
049 * {@code Readable & Closeable}. A {@link java.io.Reader} implements both of
050 * those interfaces. Similarly for {@code Appendable & Closeable} and
051 * {@link java.io.Writer}.
052 *
053 * @author Chris Nokleberg
054 * @author Bin Zhu
055 * @author Colin Decker
056 * @since 1.0
057 */
058@Beta
059public final class CharStreams {
060  private static final int BUF_SIZE = 0x800; // 2K chars (4K bytes)
061
062  private CharStreams() {}
063
064  /**
065   * Returns a factory that will supply instances of {@link StringReader} that
066   * read a string value.
067   *
068   * @param value the string to read
069   * @return the factory
070   * @deprecated Use {@link CharSource#wrap(CharSequence)} instead. This method
071   *     is scheduled for removal in Guava 18.0.
072   */
073  @Deprecated
074  public static InputSupplier<StringReader> newReaderSupplier(
075      final String value) {
076    return asInputSupplier(CharSource.wrap(value));
077  }
078
079  /**
080   * Returns a factory that will supply instances of {@link InputStreamReader},
081   * using the given {@link InputStream} factory and character set.
082   *
083   * @param in the factory that will be used to open input streams
084   * @param charset the charset used to decode the input stream; see {@link
085   *     Charsets} for helpful predefined constants
086   * @return the factory
087   * @deprecated Use {@link ByteSource#asCharSource(Charset)} instead. This
088   *     method is scheduled for removal in Guava 18.0.
089   */
090  @Deprecated
091  public static InputSupplier<InputStreamReader> newReaderSupplier(
092      final InputSupplier<? extends InputStream> in, final Charset charset) {
093    return asInputSupplier(
094        ByteStreams.asByteSource(in).asCharSource(charset));
095  }
096
097  /**
098   * Returns a factory that will supply instances of {@link OutputStreamWriter},
099   * using the given {@link OutputStream} factory and character set.
100   *
101   * @param out the factory that will be used to open output streams
102   * @param charset the charset used to encode the output stream; see {@link
103   *     Charsets} for helpful predefined constants
104   * @return the factory
105   * @deprecated Use {@link ByteSink#asCharSink(Charset)} instead. This method
106   *     is scheduled for removal in Guava 18.0.
107   */
108  @Deprecated
109  public static OutputSupplier<OutputStreamWriter> newWriterSupplier(
110      final OutputSupplier<? extends OutputStream> out, final Charset charset) {
111    return asOutputSupplier(
112        ByteStreams.asByteSink(out).asCharSink(charset));
113  }
114
115  /**
116   * Writes a character sequence (such as a string) to an appendable
117   * object from the given supplier.
118   *
119   * @param from the character sequence to write
120   * @param to the output supplier
121   * @throws IOException if an I/O error occurs
122   * @deprecated Use {@link CharSink#write(CharSequence)} instead. This method
123   *     is scheduled for removal in Guava 18.0.
124   */
125  @Deprecated
126  public static <W extends Appendable & Closeable> void write(CharSequence from,
127      OutputSupplier<W> to) throws IOException {
128    asCharSink(to).write(from);
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   * @deprecated Use {@link CharSource#copyTo(CharSink)} instead. This method is
141   *     scheduled for removal in Guava 18.0.
142   */
143  @Deprecated
144  public static <R extends Readable & Closeable,
145      W extends Appendable & Closeable> long copy(InputSupplier<R> from,
146      OutputSupplier<W> to) throws IOException {
147    return asCharSource(from).copyTo(asCharSink(to));
148  }
149
150  /**
151   * Opens a {@link Readable} object from the supplier, copies all characters
152   * to the {@link Appendable} object, and closes the input. Does not close
153   * or flush the output.
154   *
155   * @param from the input factory
156   * @param to the object to write to
157   * @return the number of characters copied
158   * @throws IOException if an I/O error occurs
159   * @deprecated Use {@link CharSource#copyTo(Appendable)} instead. This method
160   *     is scheduled for removal in Guava 18.0.
161   */
162  @Deprecated
163  public static <R extends Readable & Closeable> long copy(
164      InputSupplier<R> from, Appendable to) throws IOException {
165    return asCharSource(from).copyTo(to);
166  }
167
168  /**
169   * Copies all characters between the {@link Readable} and {@link Appendable}
170   * objects. Does not close or flush either object.
171   *
172   * @param from the object to read from
173   * @param to the object to write to
174   * @return the number of characters copied
175   * @throws IOException if an I/O error occurs
176   */
177  public static long copy(Readable from, Appendable to) throws IOException {
178    checkNotNull(from);
179    checkNotNull(to);
180    CharBuffer buf = CharBuffer.allocate(BUF_SIZE);
181    long total = 0;
182    while (from.read(buf) != -1) {
183      buf.flip();
184      to.append(buf);
185      total += buf.remaining();
186      buf.clear();
187    }
188    return total;
189  }
190
191  /**
192   * Reads all characters from a {@link Readable} object into a {@link String}.
193   * Does not close the {@code Readable}.
194   *
195   * @param r the object to read from
196   * @return a string containing all the characters
197   * @throws IOException if an I/O error occurs
198   */
199  public static String toString(Readable r) throws IOException {
200    return toStringBuilder(r).toString();
201  }
202
203  /**
204   * Returns the characters from a {@link Readable} & {@link Closeable} object
205   * supplied by a factory as a {@link String}.
206   *
207   * @param supplier the factory to read from
208   * @return a string containing all the characters
209   * @throws IOException if an I/O error occurs
210   * @deprecated Use {@link CharSource#read()} instead. This method is
211   *     scheduled for removal in Guava 18.0.
212   */
213  @Deprecated
214  public static <R extends Readable & Closeable> String toString(
215      InputSupplier<R> supplier) throws IOException {
216    return asCharSource(supplier).read();
217  }
218
219  /**
220   * Reads all characters from a {@link Readable} object into a new
221   * {@link StringBuilder} instance. Does not close the {@code Readable}.
222   *
223   * @param r the object to read from
224   * @return a {@link StringBuilder} containing all the characters
225   * @throws IOException if an I/O error occurs
226   */
227  private static StringBuilder toStringBuilder(Readable r) throws IOException {
228    StringBuilder sb = new StringBuilder();
229    copy(r, sb);
230    return sb;
231  }
232
233  /**
234   * Reads the first line from a {@link Readable} & {@link Closeable} object
235   * supplied by a factory. The line does not include line-termination
236   * characters, but does include other leading and trailing whitespace.
237   *
238   * @param supplier the factory to read from
239   * @return the first line, or null if the reader is empty
240   * @throws IOException if an I/O error occurs
241   * @deprecated Use {@link CharSource#readFirstLine()} instead. This method is
242   *     scheduled for removal in Guava 18.0.
243   */
244  @Deprecated
245  public static <R extends Readable & Closeable> String readFirstLine(
246      InputSupplier<R> supplier) throws IOException {
247    return asCharSource(supplier).readFirstLine();
248  }
249
250  /**
251   * Reads all of the lines from a {@link Readable} & {@link Closeable} object
252   * supplied by a factory. The lines do not include line-termination
253   * characters, but do include other leading and trailing whitespace.
254   *
255   * @param supplier the factory to read from
256   * @return a mutable {@link List} containing all the lines
257   * @throws IOException if an I/O error occurs
258   * @deprecated Use {@link CharSource#readLines()} instead, but note that it
259   *     returns an {@code ImmutableList}. This method is scheduled for removal
260   *     in Guava 18.0.
261   */
262  @Deprecated
263  public static <R extends Readable & Closeable> List<String> readLines(
264      InputSupplier<R> supplier) throws IOException {
265    Closer closer = Closer.create();
266    try {
267      R r = closer.register(supplier.getInput());
268      return readLines(r);
269    } catch (Throwable e) {
270      throw closer.rethrow(e);
271    } finally {
272      closer.close();
273    }
274  }
275
276  /**
277   * Reads all of the lines from a {@link Readable} object. The lines do
278   * not include line-termination characters, but do include other
279   * leading and trailing whitespace.
280   *
281   * <p>Does not close the {@code Readable}. If reading files or resources you
282   * should use the {@link Files#readLines} and {@link Resources#readLines}
283   * methods.
284   *
285   * @param r the object to read from
286   * @return a mutable {@link List} containing all the lines
287   * @throws IOException if an I/O error occurs
288   */
289  public static List<String> readLines(Readable r) throws IOException {
290    List<String> result = new ArrayList<String>();
291    LineReader lineReader = new LineReader(r);
292    String line;
293    while ((line = lineReader.readLine()) != null) {
294      result.add(line);
295    }
296    return result;
297  }
298
299  /**
300   * Streams lines from a {@link Readable} object, stopping when the processor
301   * returns {@code false} or all lines have been read and returning the result
302   * produced by the processor. Does not close {@code readable}. Note that this
303   * method may not fully consume the contents of {@code readable} if the
304   * processor stops processing early.
305   *
306   * @throws IOException if an I/O error occurs
307   * @since 14.0
308   */
309  public static <T> T readLines(
310      Readable readable, LineProcessor<T> processor) throws IOException {
311    checkNotNull(readable);
312    checkNotNull(processor);
313
314    LineReader lineReader = new LineReader(readable);
315    String line;
316    while ((line = lineReader.readLine()) != null) {
317      if (!processor.processLine(line)) {
318        break;
319      }
320    }
321    return processor.getResult();
322  }
323
324  /**
325   * Streams lines from a {@link Readable} and {@link Closeable} object
326   * supplied by a factory, stopping when our callback returns false, or we
327   * have read all of the lines.
328   *
329   * @param supplier the factory to read from
330   * @param callback the LineProcessor to use to handle the lines
331   * @return the output of processing the lines
332   * @throws IOException if an I/O error occurs
333   * @deprecated Use {@link CharSource#readLines(LineProcessor)} instead. This
334   *     method is scheduled for removal in Guava 18.0.
335   */
336  @Deprecated
337  public static <R extends Readable & Closeable, T> T readLines(
338      InputSupplier<R> supplier, LineProcessor<T> callback) throws IOException {
339    checkNotNull(supplier);
340    checkNotNull(callback);
341
342    Closer closer = Closer.create();
343    try {
344      R r = closer.register(supplier.getInput());
345      return readLines(r, callback);
346    } catch (Throwable e) {
347      throw closer.rethrow(e);
348    } finally {
349      closer.close();
350    }
351  }
352
353  /**
354   * Joins multiple {@link Reader} suppliers into a single supplier.
355   * Reader returned from the supplier will contain the concatenated data
356   * from the readers of the underlying suppliers.
357   *
358   * <p>Reading from the joined reader will throw a {@link NullPointerException}
359   * if any of the suppliers are null or return null.
360   *
361   * <p>Only one underlying reader will be open at a time. Closing the
362   * joined reader will close the open underlying reader.
363   *
364   * @param suppliers the suppliers to concatenate
365   * @return a supplier that will return a reader containing the concatenated
366   *     data
367   * @deprecated Use {@link CharSource#concat(Iterable)} instead. This method
368   *     is scheduled for removal in Guava 18.0.
369   */
370  @Deprecated
371  public static InputSupplier<Reader> join(
372      final Iterable<? extends InputSupplier<? extends Reader>> suppliers) {
373    checkNotNull(suppliers);
374    Iterable<CharSource> sources = Iterables.transform(suppliers,
375        new Function<InputSupplier<? extends Reader>, CharSource>() {
376          @Override
377          public CharSource apply(InputSupplier<? extends Reader> input) {
378            return asCharSource(input);
379          }
380        });
381    return asInputSupplier(CharSource.concat(sources));
382  }
383
384  /**
385   * Varargs form of {@link #join(Iterable)}.
386   *
387   * @deprecated Use {@link CharSource#concat(CharSource[])} instead. This
388   *     method is scheduled for removal in Guava 18.0.
389   */
390  @Deprecated
391  @SuppressWarnings("unchecked") // suppress "possible heap pollution" warning in JDK7
392  public static InputSupplier<Reader> join(
393      InputSupplier<? extends Reader>... suppliers) {
394    return join(Arrays.asList(suppliers));
395  }
396
397  /**
398   * Discards {@code n} characters of data from the reader. This method
399   * will block until the full amount has been skipped. Does not close the
400   * reader.
401   *
402   * @param reader the reader to read from
403   * @param n the number of characters to skip
404   * @throws EOFException if this stream reaches the end before skipping all
405   *     the characters
406   * @throws IOException if an I/O error occurs
407   */
408  public static void skipFully(Reader reader, long n) throws IOException {
409    checkNotNull(reader);
410    while (n > 0) {
411      long amt = reader.skip(n);
412      if (amt == 0) {
413        // force a blocking read
414        if (reader.read() == -1) {
415          throw new EOFException();
416        }
417        n--;
418      } else {
419        n -= amt;
420      }
421    }
422  }
423
424  /**
425   * Returns a {@link Writer} that simply discards written chars.
426   *
427   * @since 15.0
428   */
429  public static Writer nullWriter() {
430    return NullWriter.INSTANCE;
431  }
432
433  private static final class NullWriter extends Writer {
434
435    private static final NullWriter INSTANCE = new NullWriter();
436
437    @Override
438    public void write(int c) {
439    }
440
441    @Override
442    public void write(char[] cbuf) {
443      checkNotNull(cbuf);
444    }
445
446    @Override
447    public void write(char[] cbuf, int off, int len) {
448      checkPositionIndexes(off, off + len, cbuf.length);
449    }
450
451    @Override
452    public void write(String str) {
453      checkNotNull(str);
454    }
455
456    @Override
457    public void write(String str, int off, int len) {
458      checkPositionIndexes(off, off + len, str.length());
459    }
460
461    @Override
462    public Writer append(CharSequence csq) {
463      checkNotNull(csq);
464      return this;
465    }
466
467    @Override
468    public Writer append(CharSequence csq, int start, int end) {
469      checkPositionIndexes(start, end, csq.length());
470      return this;
471    }
472
473    @Override
474    public Writer append(char c) {
475      return this;
476    }
477
478    @Override
479    public void flush() {
480    }
481
482    @Override
483    public void close() {
484    }
485
486    @Override
487    public String toString() {
488      return "CharStreams.nullWriter()";
489    }
490  }
491
492  /**
493   * Returns a Writer that sends all output to the given {@link Appendable}
494   * target. Closing the writer will close the target if it is {@link
495   * Closeable}, and flushing the writer will flush the target if it is {@link
496   * java.io.Flushable}.
497   *
498   * @param target the object to which output will be sent
499   * @return a new Writer object, unless target is a Writer, in which case the
500   *     target is returned
501   */
502  public static Writer asWriter(Appendable target) {
503    if (target instanceof Writer) {
504      return (Writer) target;
505    }
506    return new AppendableWriter(target);
507  }
508
509  // TODO(user): Remove these once Input/OutputSupplier methods are removed
510
511  static Reader asReader(final Readable readable) {
512    checkNotNull(readable);
513    if (readable instanceof Reader) {
514      return (Reader) readable;
515    }
516    return new Reader() {
517      @Override
518      public int read(char[] cbuf, int off, int len) throws IOException {
519        return read(CharBuffer.wrap(cbuf, off, len));
520      }
521
522      @Override
523      public int read(CharBuffer target) throws IOException {
524        return readable.read(target);
525      }
526
527      @Override
528      public void close() throws IOException {
529        if (readable instanceof Closeable) {
530          ((Closeable) readable).close();
531        }
532      }
533    };
534  }
535
536  /**
537   * Returns a view of the given {@code Readable} supplier as a
538   * {@code CharSource}.
539   *
540   * <p>This method is a temporary method provided for easing migration from
541   * suppliers to sources and sinks.
542   *
543   * @since 15.0
544   * @deprecated Convert all {@code InputSupplier<? extends Readable>}
545   *     implementations to extend {@link CharSource} or provide a method for
546   *     viewing the object as a {@code CharSource}. This method is scheduled
547   *     for removal in Guava 18.0.
548   */
549  @Deprecated
550  public static CharSource asCharSource(
551      final InputSupplier<? extends Readable> supplier) {
552    checkNotNull(supplier);
553    return new CharSource() {
554      @Override
555      public Reader openStream() throws IOException {
556        return asReader(supplier.getInput());
557      }
558
559      @Override
560      public String toString() {
561        return "CharStreams.asCharSource(" + supplier + ")";
562      }
563    };
564  }
565
566  /**
567   * Returns a view of the given {@code Appendable} supplier as a
568   * {@code CharSink}.
569   *
570   * <p>This method is a temporary method provided for easing migration from
571   * suppliers to sources and sinks.
572   *
573   * @since 15.0
574   * @deprecated Convert all {@code OutputSupplier<? extends Appendable>}
575   *     implementations to extend {@link CharSink} or provide a method for
576   *     viewing the object as a {@code CharSink}. This method is scheduled
577   *     for removal in Guava 18.0.
578   */
579  @Deprecated
580  public static CharSink asCharSink(
581      final OutputSupplier<? extends Appendable> supplier) {
582    checkNotNull(supplier);
583    return new CharSink() {
584      @Override
585      public Writer openStream() throws IOException {
586        return asWriter(supplier.getOutput());
587      }
588
589      @Override
590      public String toString() {
591        return "CharStreams.asCharSink(" + supplier + ")";
592      }
593    };
594  }
595
596  @SuppressWarnings("unchecked") // used internally where known to be safe
597  static <R extends Reader> InputSupplier<R> asInputSupplier(
598      CharSource source) {
599    return (InputSupplier) checkNotNull(source);
600  }
601
602  @SuppressWarnings("unchecked") // used internally where known to be safe
603  static <W extends Writer> OutputSupplier<W> asOutputSupplier(
604      CharSink sink) {
605    return (OutputSupplier) checkNotNull(sink);
606  }
607}