Home | History | Annotate | Download | only in io
      1 /*
      2  * Copyright (C) 2007 The Guava Authors
      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 static com.google.common.base.Preconditions.checkNotNull;
     20 import static com.google.common.base.Preconditions.checkPositionIndexes;
     21 
     22 import com.google.common.annotations.Beta;
     23 
     24 import java.io.Closeable;
     25 import java.io.EOFException;
     26 import java.io.IOException;
     27 import java.io.Reader;
     28 import java.io.Writer;
     29 import java.nio.CharBuffer;
     30 import java.util.ArrayList;
     31 import java.util.List;
     32 
     33 /**
     34  * Provides utility methods for working with character streams.
     35  *
     36  * <p>All method parameters must be non-null unless documented otherwise.
     37  *
     38  * <p>Some of the methods in this class take arguments with a generic type of
     39  * {@code Readable & Closeable}. A {@link java.io.Reader} implements both of
     40  * those interfaces. Similarly for {@code Appendable & Closeable} and
     41  * {@link java.io.Writer}.
     42  *
     43  * @author Chris Nokleberg
     44  * @author Bin Zhu
     45  * @author Colin Decker
     46  * @since 1.0
     47  */
     48 @Beta
     49 public final class CharStreams {
     50   private static final int BUF_SIZE = 0x800; // 2K chars (4K bytes)
     51 
     52   private CharStreams() {}
     53 
     54   /**
     55    * Copies all characters between the {@link Readable} and {@link Appendable}
     56    * objects. Does not close or flush either object.
     57    *
     58    * @param from the object to read from
     59    * @param to the object to write to
     60    * @return the number of characters copied
     61    * @throws IOException if an I/O error occurs
     62    */
     63   public static long copy(Readable from, Appendable to) throws IOException {
     64     checkNotNull(from);
     65     checkNotNull(to);
     66     CharBuffer buf = CharBuffer.allocate(BUF_SIZE);
     67     long total = 0;
     68     while (from.read(buf) != -1) {
     69       buf.flip();
     70       to.append(buf);
     71       total += buf.remaining();
     72       buf.clear();
     73     }
     74     return total;
     75   }
     76 
     77   /**
     78    * Reads all characters from a {@link Readable} object into a {@link String}.
     79    * Does not close the {@code Readable}.
     80    *
     81    * @param r the object to read from
     82    * @return a string containing all the characters
     83    * @throws IOException if an I/O error occurs
     84    */
     85   public static String toString(Readable r) throws IOException {
     86     return toStringBuilder(r).toString();
     87   }
     88 
     89   /**
     90    * Reads all characters from a {@link Readable} object into a new
     91    * {@link StringBuilder} instance. Does not close the {@code Readable}.
     92    *
     93    * @param r the object to read from
     94    * @return a {@link StringBuilder} containing all the characters
     95    * @throws IOException if an I/O error occurs
     96    */
     97   private static StringBuilder toStringBuilder(Readable r) throws IOException {
     98     StringBuilder sb = new StringBuilder();
     99     copy(r, sb);
    100     return sb;
    101   }
    102 
    103   /**
    104    * Reads all of the lines from a {@link Readable} object. The lines do
    105    * not include line-termination characters, but do include other
    106    * leading and trailing whitespace.
    107    *
    108    * <p>Does not close the {@code Readable}. If reading files or resources you
    109    * should use the {@link Files#readLines} and {@link Resources#readLines}
    110    * methods.
    111    *
    112    * @param r the object to read from
    113    * @return a mutable {@link List} containing all the lines
    114    * @throws IOException if an I/O error occurs
    115    */
    116   public static List<String> readLines(Readable r) throws IOException {
    117     List<String> result = new ArrayList<String>();
    118     LineReader lineReader = new LineReader(r);
    119     String line;
    120     while ((line = lineReader.readLine()) != null) {
    121       result.add(line);
    122     }
    123     return result;
    124   }
    125 
    126   /**
    127    * Streams lines from a {@link Readable} object, stopping when the processor
    128    * returns {@code false} or all lines have been read and returning the result
    129    * produced by the processor. Does not close {@code readable}. Note that this
    130    * method may not fully consume the contents of {@code readable} if the
    131    * processor stops processing early.
    132    *
    133    * @throws IOException if an I/O error occurs
    134    * @since 14.0
    135    */
    136   public static <T> T readLines(
    137       Readable readable, LineProcessor<T> processor) throws IOException {
    138     checkNotNull(readable);
    139     checkNotNull(processor);
    140 
    141     LineReader lineReader = new LineReader(readable);
    142     String line;
    143     while ((line = lineReader.readLine()) != null) {
    144       if (!processor.processLine(line)) {
    145         break;
    146       }
    147     }
    148     return processor.getResult();
    149   }
    150 
    151   /**
    152    * Discards {@code n} characters of data from the reader. This method
    153    * will block until the full amount has been skipped. Does not close the
    154    * reader.
    155    *
    156    * @param reader the reader to read from
    157    * @param n the number of characters to skip
    158    * @throws EOFException if this stream reaches the end before skipping all
    159    *     the characters
    160    * @throws IOException if an I/O error occurs
    161    */
    162   public static void skipFully(Reader reader, long n) throws IOException {
    163     checkNotNull(reader);
    164     while (n > 0) {
    165       long amt = reader.skip(n);
    166       if (amt == 0) {
    167         // force a blocking read
    168         if (reader.read() == -1) {
    169           throw new EOFException();
    170         }
    171         n--;
    172       } else {
    173         n -= amt;
    174       }
    175     }
    176   }
    177 
    178   /**
    179    * Returns a {@link Writer} that simply discards written chars.
    180    *
    181    * @since 15.0
    182    */
    183   public static Writer nullWriter() {
    184     return NullWriter.INSTANCE;
    185   }
    186 
    187   private static final class NullWriter extends Writer {
    188 
    189     private static final NullWriter INSTANCE = new NullWriter();
    190 
    191     @Override
    192     public void write(int c) {
    193     }
    194 
    195     @Override
    196     public void write(char[] cbuf) {
    197       checkNotNull(cbuf);
    198     }
    199 
    200     @Override
    201     public void write(char[] cbuf, int off, int len) {
    202       checkPositionIndexes(off, off + len, cbuf.length);
    203     }
    204 
    205     @Override
    206     public void write(String str) {
    207       checkNotNull(str);
    208     }
    209 
    210     @Override
    211     public void write(String str, int off, int len) {
    212       checkPositionIndexes(off, off + len, str.length());
    213     }
    214 
    215     @Override
    216     public Writer append(CharSequence csq) {
    217       checkNotNull(csq);
    218       return this;
    219     }
    220 
    221     @Override
    222     public Writer append(CharSequence csq, int start, int end) {
    223       checkPositionIndexes(start, end, csq.length());
    224       return this;
    225     }
    226 
    227     @Override
    228     public Writer append(char c) {
    229       return this;
    230     }
    231 
    232     @Override
    233     public void flush() {
    234     }
    235 
    236     @Override
    237     public void close() {
    238     }
    239 
    240     @Override
    241     public String toString() {
    242       return "CharStreams.nullWriter()";
    243     }
    244   }
    245 
    246   /**
    247    * Returns a Writer that sends all output to the given {@link Appendable}
    248    * target. Closing the writer will close the target if it is {@link
    249    * Closeable}, and flushing the writer will flush the target if it is {@link
    250    * java.io.Flushable}.
    251    *
    252    * @param target the object to which output will be sent
    253    * @return a new Writer object, unless target is a Writer, in which case the
    254    *     target is returned
    255    */
    256   public static Writer asWriter(Appendable target) {
    257     if (target instanceof Writer) {
    258       return (Writer) target;
    259     }
    260     return new AppendableWriter(target);
    261   }
    262 
    263   // TODO(user): Remove these once Input/OutputSupplier methods are removed
    264 
    265   static Reader asReader(final Readable readable) {
    266     checkNotNull(readable);
    267     if (readable instanceof Reader) {
    268       return (Reader) readable;
    269     }
    270     return new Reader() {
    271       @Override
    272       public int read(char[] cbuf, int off, int len) throws IOException {
    273         return read(CharBuffer.wrap(cbuf, off, len));
    274       }
    275 
    276       @Override
    277       public int read(CharBuffer target) throws IOException {
    278         return readable.read(target);
    279       }
    280 
    281       @Override
    282       public void close() throws IOException {
    283         if (readable instanceof Closeable) {
    284           ((Closeable) readable).close();
    285         }
    286       }
    287     };
    288   }
    289 }
    290