View Javadoc
1   /*
2    * Copyright (C) 2007 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5    * in compliance with the License. You may obtain a copy of the License at
6    *
7    * http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software distributed under the License
10   * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11   * or implied. See the License for the specific language governing permissions and limitations under
12   * the License.
13   */
14  
15  package com.google.common.io;
16  
17  import static com.google.common.base.Preconditions.checkNotNull;
18  import static com.google.common.base.Preconditions.checkPositionIndexes;
19  
20  import com.google.common.annotations.Beta;
21  import com.google.common.annotations.GwtIncompatible;
22  import com.google.errorprone.annotations.CanIgnoreReturnValue;
23  import java.io.Closeable;
24  import java.io.EOFException;
25  import java.io.IOException;
26  import java.io.Reader;
27  import java.io.Writer;
28  import java.nio.CharBuffer;
29  import java.util.ArrayList;
30  import java.util.List;
31  
32  /**
33   * Provides utility methods for working with character streams.
34   *
35   * <p>All method parameters must be non-null unless documented otherwise.
36   *
37   * <p>Some of the methods in this class take arguments with a generic type of
38   * {@code Readable & Closeable}. A {@link java.io.Reader} implements both of those interfaces.
39   * Similarly for {@code Appendable & Closeable} and {@link java.io.Writer}.
40   *
41   * @author Chris Nokleberg
42   * @author Bin Zhu
43   * @author Colin Decker
44   * @since 1.0
45   */
46  @Beta
47  @GwtIncompatible
48  public final class CharStreams {
49  
50    // 2K chars (4K bytes)
51    private static final int DEFAULT_BUF_SIZE = 0x800;
52  
53    /**
54     * Creates a new {@code CharBuffer} for buffering reads or writes.
55     */
56    static CharBuffer createBuffer() {
57      return CharBuffer.allocate(DEFAULT_BUF_SIZE);
58    }
59  
60    private CharStreams() {}
61  
62    /**
63     * Copies all characters between the {@link Readable} and {@link Appendable} objects. Does not
64     * close or flush either object.
65     *
66     * @param from the object to read from
67     * @param to the object to write to
68     * @return the number of characters copied
69     * @throws IOException if an I/O error occurs
70     */
71    @CanIgnoreReturnValue
72    public static long copy(Readable from, Appendable to) throws IOException {
73      // The most common case is that from is a Reader (like InputStreamReader or StringReader) so
74      // take advantage of that.
75      if (from instanceof Reader) {
76        // optimize for common output types which are optimized to deal with char[]
77        if (to instanceof StringBuilder) {
78          return copyReaderToBuilder((Reader) from, (StringBuilder) to);
79        } else {
80          return copyReaderToWriter((Reader) from, asWriter(to));
81        }
82      } else {
83        checkNotNull(from);
84        checkNotNull(to);
85        long total = 0;
86        CharBuffer buf = createBuffer();
87        while (from.read(buf) != -1) {
88          buf.flip();
89          to.append(buf);
90          total += buf.remaining();
91          buf.clear();
92        }
93        return total;
94      }
95    }
96  
97    // TODO(lukes): consider allowing callers to pass in a buffer to use, some callers would be able
98    // to reuse buffers, others would be able to size them more appropriately than the constant
99    // defaults
100 
101   /**
102    * Copies all characters between the {@link Reader} and {@link StringBuilder} objects. Does not
103    * close or flush the reader.
104    *
105    * <p>This is identical to {@link #copy(Readable, Appendable)} but optimized for these specific
106    * types. CharBuffer has poor performance when being written into or read out of so round tripping
107    * all the bytes through the buffer takes a long time. With these specialized types we can just
108    * use a char array.
109    *
110    * @param from the object to read from
111    * @param to the object to write to
112    * @return the number of characters copied
113    * @throws IOException if an I/O error occurs
114    */
115   @CanIgnoreReturnValue
116   static long copyReaderToBuilder(Reader from, StringBuilder to) throws IOException {
117     checkNotNull(from);
118     checkNotNull(to);
119     char[] buf = new char[DEFAULT_BUF_SIZE];
120     int nRead;
121     long total = 0;
122     while ((nRead = from.read(buf)) != -1) {
123       to.append(buf, 0, nRead);
124       total += nRead;
125     }
126     return total;
127   }
128 
129   /**
130    * Copies all characters between the {@link Reader} and {@link Writer} objects. Does not close or
131    * flush the reader or writer.
132    *
133    * <p>This is identical to {@link #copy(Readable, Appendable)} but optimized for these specific
134    * types. CharBuffer has poor performance when being written into or read out of so round tripping
135    * all the bytes through the buffer takes a long time. With these specialized types we can just
136    * use a char array.
137    *
138    * @param from the object to read from
139    * @param to the object to write to
140    * @return the number of characters copied
141    * @throws IOException if an I/O error occurs
142    */
143   @CanIgnoreReturnValue
144   static long copyReaderToWriter(Reader from, Writer to) throws IOException {
145     checkNotNull(from);
146     checkNotNull(to);
147     char[] buf = new char[DEFAULT_BUF_SIZE];
148     int nRead;
149     long total = 0;
150     while ((nRead = from.read(buf)) != -1) {
151       to.write(buf, 0, nRead);
152       total += nRead;
153     }
154     return total;
155   }
156 
157   /**
158    * Reads all characters from a {@link Readable} object into a {@link String}. Does not close the
159    * {@code Readable}.
160    *
161    * @param r the object to read from
162    * @return a string containing all the characters
163    * @throws IOException if an I/O error occurs
164    */
165   public static String toString(Readable r) throws IOException {
166     return toStringBuilder(r).toString();
167   }
168 
169   /**
170    * Reads all characters from a {@link Readable} object into a new {@link StringBuilder} instance.
171    * Does not close the {@code Readable}.
172    *
173    * @param r the object to read from
174    * @return a {@link StringBuilder} containing all the characters
175    * @throws IOException if an I/O error occurs
176    */
177   private static StringBuilder toStringBuilder(Readable r) throws IOException {
178     StringBuilder sb = new StringBuilder();
179     if (r instanceof Reader) {
180       copyReaderToBuilder((Reader) r, sb);
181     } else {
182       copy(r, sb);
183     }
184     return sb;
185   }
186 
187   /**
188    * Reads all of the lines from a {@link Readable} object. The lines do not include
189    * line-termination characters, but do include other leading and trailing whitespace.
190    *
191    * <p>Does not close the {@code Readable}. If reading files or resources you should use the
192    * {@link Files#readLines} and {@link Resources#readLines} methods.
193    *
194    * @param r the object to read from
195    * @return a mutable {@link List} containing all the lines
196    * @throws IOException if an I/O error occurs
197    */
198   public static List<String> readLines(Readable r) throws IOException {
199     List<String> result = new ArrayList<>();
200     LineReader lineReader = new LineReader(r);
201     String line;
202     while ((line = lineReader.readLine()) != null) {
203       result.add(line);
204     }
205     return result;
206   }
207 
208   /**
209    * Streams lines from a {@link Readable} object, stopping when the processor returns {@code false}
210    * or all lines have been read and returning the result produced by the processor. Does not close
211    * {@code readable}. Note that this method may not fully consume the contents of {@code readable}
212    * if the processor stops processing early.
213    *
214    * @throws IOException if an I/O error occurs
215    * @since 14.0
216    */
217   @CanIgnoreReturnValue // some processors won't return a useful result
218   public static <T> T readLines(Readable readable, LineProcessor<T> processor) throws IOException {
219     checkNotNull(readable);
220     checkNotNull(processor);
221 
222     LineReader lineReader = new LineReader(readable);
223     String line;
224     while ((line = lineReader.readLine()) != null) {
225       if (!processor.processLine(line)) {
226         break;
227       }
228     }
229     return processor.getResult();
230   }
231 
232   /**
233    * Reads and discards data from the given {@code Readable} until the end of the stream is
234    * reached. Returns the total number of chars read. Does not close the stream.
235    *
236    * @since 20.0
237    */
238   @CanIgnoreReturnValue
239   public static long exhaust(Readable readable) throws IOException {
240     long total = 0;
241     long read;
242     CharBuffer buf = createBuffer();
243     while ((read = readable.read(buf)) != -1) {
244       total += read;
245       buf.clear();
246     }
247     return total;
248   }
249 
250   /**
251    * Discards {@code n} characters of data from the reader. This method will block until the full
252    * amount has been skipped. Does not close the reader.
253    *
254    * @param reader the reader to read from
255    * @param n the number of characters to skip
256    * @throws EOFException if this stream reaches the end before skipping all the characters
257    * @throws IOException if an I/O error occurs
258    */
259   public static void skipFully(Reader reader, long n) throws IOException {
260     checkNotNull(reader);
261     while (n > 0) {
262       long amt = reader.skip(n);
263       if (amt == 0) {
264         throw new EOFException();
265       }
266       n -= amt;
267     }
268   }
269 
270   /**
271    * Returns a {@link Writer} that simply discards written chars.
272    *
273    * @since 15.0
274    */
275   public static Writer nullWriter() {
276     return NullWriter.INSTANCE;
277   }
278 
279   private static final class NullWriter extends Writer {
280 
281     private static final NullWriter INSTANCE = new NullWriter();
282 
283     @Override
284     public void write(int c) {}
285 
286     @Override
287     public void write(char[] cbuf) {
288       checkNotNull(cbuf);
289     }
290 
291     @Override
292     public void write(char[] cbuf, int off, int len) {
293       checkPositionIndexes(off, off + len, cbuf.length);
294     }
295 
296     @Override
297     public void write(String str) {
298       checkNotNull(str);
299     }
300 
301     @Override
302     public void write(String str, int off, int len) {
303       checkPositionIndexes(off, off + len, str.length());
304     }
305 
306     @Override
307     public Writer append(CharSequence csq) {
308       checkNotNull(csq);
309       return this;
310     }
311 
312     @Override
313     public Writer append(CharSequence csq, int start, int end) {
314       checkPositionIndexes(start, end, csq.length());
315       return this;
316     }
317 
318     @Override
319     public Writer append(char c) {
320       return this;
321     }
322 
323     @Override
324     public void flush() {}
325 
326     @Override
327     public void close() {}
328 
329     @Override
330     public String toString() {
331       return "CharStreams.nullWriter()";
332     }
333   }
334 
335   /**
336    * Returns a Writer that sends all output to the given {@link Appendable} target. Closing the
337    * writer will close the target if it is {@link Closeable}, and flushing the writer will flush the
338    * target if it is {@link java.io.Flushable}.
339    *
340    * @param target the object to which output will be sent
341    * @return a new Writer object, unless target is a Writer, in which case the target is returned
342    */
343   public static Writer asWriter(Appendable target) {
344     if (target instanceof Writer) {
345       return (Writer) target;
346     }
347     return new AppendableWriter(target);
348   }
349 }