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