• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CharStreams()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    */
copy(Readable from, Appendable to)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    */
toString(Readable r)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    */
toStringBuilder(Readable r)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    */
readLines(Readable r)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    */
readLines( Readable readable, LineProcessor<T> processor)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    */
skipFully(Reader reader, long n)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    */
nullWriter()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
write(int c)192     public void write(int c) {
193     }
194 
195     @Override
write(char[] cbuf)196     public void write(char[] cbuf) {
197       checkNotNull(cbuf);
198     }
199 
200     @Override
write(char[] cbuf, int off, int len)201     public void write(char[] cbuf, int off, int len) {
202       checkPositionIndexes(off, off + len, cbuf.length);
203     }
204 
205     @Override
write(String str)206     public void write(String str) {
207       checkNotNull(str);
208     }
209 
210     @Override
write(String str, int off, int len)211     public void write(String str, int off, int len) {
212       checkPositionIndexes(off, off + len, str.length());
213     }
214 
215     @Override
append(CharSequence csq)216     public Writer append(CharSequence csq) {
217       checkNotNull(csq);
218       return this;
219     }
220 
221     @Override
append(CharSequence csq, int start, int end)222     public Writer append(CharSequence csq, int start, int end) {
223       checkPositionIndexes(start, end, csq.length());
224       return this;
225     }
226 
227     @Override
append(char c)228     public Writer append(char c) {
229       return this;
230     }
231 
232     @Override
flush()233     public void flush() {
234     }
235 
236     @Override
close()237     public void close() {
238     }
239 
240     @Override
toString()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    */
asWriter(Appendable target)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 
asReader(final Readable readable)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