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; 020 021import com.google.common.annotations.Beta; 022import com.google.common.base.Charsets; 023import com.google.common.base.Splitter; 024import com.google.common.collect.AbstractIterator; 025import com.google.common.collect.ImmutableList; 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.Iterator; 042import java.util.List; 043import java.util.regex.Pattern; 044 045/** 046 * Provides utility methods for working with character streams. 047 * 048 * <p>All method parameters must be non-null unless documented otherwise. 049 * 050 * <p>Some of the methods in this class take arguments with a generic type of 051 * {@code Readable & Closeable}. A {@link java.io.Reader} implements both of 052 * those interfaces. Similarly for {@code Appendable & Closeable} and 053 * {@link java.io.Writer}. 054 * 055 * @author Chris Nokleberg 056 * @author Bin Zhu 057 * @author Colin Decker 058 * @since 1.0 059 */ 060@Beta 061public final class CharStreams { 062 private static final int BUF_SIZE = 0x800; // 2K chars (4K bytes) 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 */ 073 public static InputSupplier<StringReader> newReaderSupplier( 074 final String value) { 075 return CharStreams.asInputSupplier(asCharSource(value)); 076 } 077 078 /** 079 * Returns a {@link CharSource} that reads the given string value. 080 * 081 * @since 14.0 082 */ 083 public static CharSource asCharSource(String string) { 084 return new StringCharSource(string); 085 } 086 087 private static final class StringCharSource extends CharSource { 088 089 private static final Splitter LINE_SPLITTER 090 = Splitter.on(Pattern.compile("\r\n|\n|\r")); 091 092 private final String string; 093 094 private StringCharSource(String string) { 095 this.string = checkNotNull(string); 096 } 097 098 @Override 099 public Reader openStream() { 100 return new StringReader(string); 101 } 102 103 @Override 104 public String read() { 105 return string; 106 } 107 108 /** 109 * Returns an iterable over the lines in the string. If the string ends in 110 * a newline, a final empty string is not included to match the behavior of 111 * BufferedReader/LineReader.readLine(). 112 */ 113 private Iterable<String> lines() { 114 return new Iterable<String>() { 115 @Override 116 public Iterator<String> iterator() { 117 return new AbstractIterator<String>() { 118 Iterator<String> lines = LINE_SPLITTER.split(string).iterator(); 119 120 @Override 121 protected String computeNext() { 122 if (lines.hasNext()) { 123 String next = lines.next(); 124 // skip last line if it's empty 125 if (lines.hasNext() || !next.isEmpty()) { 126 return next; 127 } 128 } 129 return endOfData(); 130 } 131 }; 132 } 133 }; 134 } 135 136 @Override 137 public String readFirstLine() { 138 Iterator<String> lines = lines().iterator(); 139 return lines.hasNext() ? lines.next() : null; 140 } 141 142 @Override 143 public ImmutableList<String> readLines() { 144 return ImmutableList.copyOf(lines()); 145 } 146 147 @Override 148 public String toString() { 149 String limited = (string.length() <= 15) 150 ? string 151 : string.substring(0, 12) + "..."; 152 return "CharStreams.asCharSource(" + limited + ")"; 153 } 154 } 155 156 /** 157 * Returns a factory that will supply instances of {@link InputStreamReader}, 158 * using the given {@link InputStream} factory and character set. 159 * 160 * @param in the factory that will be used to open input streams 161 * @param charset the charset used to decode the input stream; see {@link 162 * Charsets} for helpful predefined constants 163 * @return the factory 164 */ 165 public static InputSupplier<InputStreamReader> newReaderSupplier( 166 final InputSupplier<? extends InputStream> in, final Charset charset) { 167 return CharStreams.asInputSupplier( 168 ByteStreams.asByteSource(in).asCharSource(charset)); 169 } 170 171 /** 172 * Returns a factory that will supply instances of {@link OutputStreamWriter}, 173 * using the given {@link OutputStream} factory and character set. 174 * 175 * @param out the factory that will be used to open output streams 176 * @param charset the charset used to encode the output stream; see {@link 177 * Charsets} for helpful predefined constants 178 * @return the factory 179 */ 180 public static OutputSupplier<OutputStreamWriter> newWriterSupplier( 181 final OutputSupplier<? extends OutputStream> out, final Charset charset) { 182 return CharStreams.asOutputSupplier( 183 ByteStreams.asByteSink(out).asCharSink(charset)); 184 } 185 186 /** 187 * Writes a character sequence (such as a string) to an appendable 188 * object from the given supplier. 189 * 190 * @param from the character sequence to write 191 * @param to the output supplier 192 * @throws IOException if an I/O error occurs 193 */ 194 public static <W extends Appendable & Closeable> void write(CharSequence from, 195 OutputSupplier<W> to) throws IOException { 196 asCharSink(to).write(from); 197 } 198 199 /** 200 * Opens {@link Readable} and {@link Appendable} objects from the 201 * given factories, copies all characters between the two, and closes 202 * them. 203 * 204 * @param from the input factory 205 * @param to the output factory 206 * @return the number of characters copied 207 * @throws IOException if an I/O error occurs 208 */ 209 public static <R extends Readable & Closeable, 210 W extends Appendable & Closeable> long copy(InputSupplier<R> from, 211 OutputSupplier<W> to) throws IOException { 212 return asCharSource(from).copyTo(asCharSink(to)); 213 } 214 215 /** 216 * Opens a {@link Readable} object from the supplier, copies all characters 217 * to the {@link Appendable} object, and closes the input. Does not close 218 * or flush the output. 219 * 220 * @param from the input factory 221 * @param to the object to write to 222 * @return the number of characters copied 223 * @throws IOException if an I/O error occurs 224 */ 225 public static <R extends Readable & Closeable> long copy( 226 InputSupplier<R> from, Appendable to) throws IOException { 227 return asCharSource(from).copyTo(to); 228 } 229 230 /** 231 * Copies all characters between the {@link Readable} and {@link Appendable} 232 * objects. Does not close or flush either object. 233 * 234 * @param from the object to read from 235 * @param to the object to write to 236 * @return the number of characters copied 237 * @throws IOException if an I/O error occurs 238 */ 239 public static long copy(Readable from, Appendable to) throws IOException { 240 checkNotNull(from); 241 checkNotNull(to); 242 CharBuffer buf = CharBuffer.allocate(BUF_SIZE); 243 long total = 0; 244 while (from.read(buf) != -1) { 245 buf.flip(); 246 to.append(buf); 247 total += buf.remaining(); 248 buf.clear(); 249 } 250 return total; 251 } 252 253 /** 254 * Reads all characters from a {@link Readable} object into a {@link String}. 255 * Does not close the {@code Readable}. 256 * 257 * @param r the object to read from 258 * @return a string containing all the characters 259 * @throws IOException if an I/O error occurs 260 */ 261 public static String toString(Readable r) throws IOException { 262 return toStringBuilder(r).toString(); 263 } 264 265 /** 266 * Returns the characters from a {@link Readable} & {@link Closeable} object 267 * supplied by a factory as a {@link String}. 268 * 269 * @param supplier the factory to read from 270 * @return a string containing all the characters 271 * @throws IOException if an I/O error occurs 272 */ 273 public static <R extends Readable & Closeable> String toString( 274 InputSupplier<R> supplier) throws IOException { 275 return asCharSource(supplier).read(); 276 } 277 278 /** 279 * Reads all characters from a {@link Readable} object into a new 280 * {@link StringBuilder} instance. Does not close the {@code Readable}. 281 * 282 * @param r the object to read from 283 * @return a {@link StringBuilder} containing all the characters 284 * @throws IOException if an I/O error occurs 285 */ 286 private static StringBuilder toStringBuilder(Readable r) throws IOException { 287 StringBuilder sb = new StringBuilder(); 288 copy(r, sb); 289 return sb; 290 } 291 292 /** 293 * Reads the first line from a {@link Readable} & {@link Closeable} object 294 * supplied by a factory. The line does not include line-termination 295 * characters, but does include other leading and trailing whitespace. 296 * 297 * @param supplier the factory to read from 298 * @return the first line, or null if the reader is empty 299 * @throws IOException if an I/O error occurs 300 */ 301 public static <R extends Readable & Closeable> String readFirstLine( 302 InputSupplier<R> supplier) throws IOException { 303 return asCharSource(supplier).readFirstLine(); 304 } 305 306 /** 307 * Reads all of the lines from a {@link Readable} & {@link Closeable} object 308 * supplied by a factory. The lines do not include line-termination 309 * characters, but do include other leading and trailing whitespace. 310 * 311 * @param supplier the factory to read from 312 * @return a mutable {@link List} containing all the lines 313 * @throws IOException if an I/O error occurs 314 */ 315 public static <R extends Readable & Closeable> List<String> readLines( 316 InputSupplier<R> supplier) throws IOException { 317 Closer closer = Closer.create(); 318 try { 319 R r = closer.register(supplier.getInput()); 320 return readLines(r); 321 } catch (Throwable e) { 322 throw closer.rethrow(e); 323 } finally { 324 closer.close(); 325 } 326 } 327 328 /** 329 * Reads all of the lines from a {@link Readable} object. The lines do 330 * not include line-termination characters, but do include other 331 * leading and trailing whitespace. 332 * 333 * <p>Does not close the {@code Readable}. If reading files or resources you 334 * should use the {@link Files#readLines} and {@link Resources#readLines} 335 * methods. 336 * 337 * @param r the object to read from 338 * @return a mutable {@link List} containing all the lines 339 * @throws IOException if an I/O error occurs 340 */ 341 public static List<String> readLines(Readable r) throws IOException { 342 List<String> result = new ArrayList<String>(); 343 LineReader lineReader = new LineReader(r); 344 String line; 345 while ((line = lineReader.readLine()) != null) { 346 result.add(line); 347 } 348 return result; 349 } 350 351 /** 352 * Streams lines from a {@link Readable} object, stopping when the processor 353 * returns {@code false} or all lines have been read and returning the result 354 * produced by the processor. Does not close {@code readable}. Note that this 355 * method may not fully consume the contents of {@code readable} if the 356 * processor stops processing early. 357 * 358 * @throws IOException if an I/O error occurs 359 * @since 14.0 360 */ 361 public static <T> T readLines( 362 Readable readable, LineProcessor<T> processor) throws IOException { 363 checkNotNull(readable); 364 checkNotNull(processor); 365 366 LineReader lineReader = new LineReader(readable); 367 String line; 368 while ((line = lineReader.readLine()) != null) { 369 if (!processor.processLine(line)) { 370 break; 371 } 372 } 373 return processor.getResult(); 374 } 375 376 /** 377 * Streams lines from a {@link Readable} and {@link Closeable} object 378 * supplied by a factory, stopping when our callback returns false, or we 379 * have read all of the lines. 380 * 381 * @param supplier the factory to read from 382 * @param callback the LineProcessor to use to handle the lines 383 * @return the output of processing the lines 384 * @throws IOException if an I/O error occurs 385 */ 386 public static <R extends Readable & Closeable, T> T readLines( 387 InputSupplier<R> supplier, LineProcessor<T> callback) throws IOException { 388 checkNotNull(supplier); 389 checkNotNull(callback); 390 391 Closer closer = Closer.create(); 392 try { 393 R r = closer.register(supplier.getInput()); 394 return readLines(r, callback); 395 } catch (Throwable e) { 396 throw closer.rethrow(e); 397 } finally { 398 closer.close(); 399 } 400 } 401 402 /** 403 * Joins multiple {@link Reader} suppliers into a single supplier. 404 * Reader returned from the supplier will contain the concatenated data 405 * from the readers of the underlying suppliers. 406 * 407 * <p>Reading from the joined reader will throw a {@link NullPointerException} 408 * if any of the suppliers are null or return null. 409 * 410 * <p>Only one underlying reader will be open at a time. Closing the 411 * joined reader will close the open underlying reader. 412 * 413 * @param suppliers the suppliers to concatenate 414 * @return a supplier that will return a reader containing the concatenated 415 * data 416 */ 417 public static InputSupplier<Reader> join( 418 final Iterable<? extends InputSupplier<? extends Reader>> suppliers) { 419 checkNotNull(suppliers); 420 return new InputSupplier<Reader>() { 421 @Override public Reader getInput() throws IOException { 422 return new MultiReader(suppliers.iterator()); 423 } 424 }; 425 } 426 427 /** Varargs form of {@link #join(Iterable)}. */ 428 public static InputSupplier<Reader> join( 429 InputSupplier<? extends Reader>... suppliers) { 430 return join(Arrays.asList(suppliers)); 431 } 432 433 /** 434 * Discards {@code n} characters of data from the reader. This method 435 * will block until the full amount has been skipped. Does not close the 436 * reader. 437 * 438 * @param reader the reader to read from 439 * @param n the number of characters to skip 440 * @throws EOFException if this stream reaches the end before skipping all 441 * the bytes 442 * @throws IOException if an I/O error occurs 443 */ 444 public static void skipFully(Reader reader, long n) throws IOException { 445 checkNotNull(reader); 446 while (n > 0) { 447 long amt = reader.skip(n); 448 if (amt == 0) { 449 // force a blocking read 450 if (reader.read() == -1) { 451 throw new EOFException(); 452 } 453 n--; 454 } else { 455 n -= amt; 456 } 457 } 458 } 459 460 /** 461 * Returns a Writer that sends all output to the given {@link Appendable} 462 * target. Closing the writer will close the target if it is {@link 463 * Closeable}, and flushing the writer will flush the target if it is {@link 464 * java.io.Flushable}. 465 * 466 * @param target the object to which output will be sent 467 * @return a new Writer object, unless target is a Writer, in which case the 468 * target is returned 469 */ 470 public static Writer asWriter(Appendable target) { 471 if (target instanceof Writer) { 472 return (Writer) target; 473 } 474 return new AppendableWriter(target); 475 } 476 477 // TODO(user): Remove these once Input/OutputSupplier methods are removed 478 479 static <R extends Readable & Closeable> Reader asReader(final R readable) { 480 checkNotNull(readable); 481 if (readable instanceof Reader) { 482 return (Reader) readable; 483 } 484 return new Reader() { 485 @Override 486 public int read(char[] cbuf, int off, int len) throws IOException { 487 return read(CharBuffer.wrap(cbuf, off, len)); 488 } 489 490 @Override 491 public int read(CharBuffer target) throws IOException { 492 return readable.read(target); 493 } 494 495 @Override 496 public void close() throws IOException { 497 readable.close(); 498 } 499 }; 500 } 501 502 static <R extends Reader> InputSupplier<R> asInputSupplier( 503 final CharSource source) { 504 checkNotNull(source); 505 return new InputSupplier<R>() { 506 @Override 507 public R getInput() throws IOException { 508 return (R) source.openStream(); 509 } 510 }; 511 } 512 513 static <W extends Writer> OutputSupplier<W> asOutputSupplier( 514 final CharSink sink) { 515 checkNotNull(sink); 516 return new OutputSupplier<W>() { 517 @Override 518 public W getOutput() throws IOException { 519 return (W) sink.openStream(); 520 } 521 }; 522 } 523 524 static <R extends Readable & Closeable> CharSource asCharSource( 525 final InputSupplier<R> supplier) { 526 checkNotNull(supplier); 527 return new CharSource() { 528 @Override 529 public Reader openStream() throws IOException { 530 return asReader(supplier.getInput()); 531 } 532 }; 533 } 534 535 static <W extends Appendable & Closeable> CharSink asCharSink( 536 final OutputSupplier<W> supplier) { 537 checkNotNull(supplier); 538 return new CharSink() { 539 @Override 540 public Writer openStream() throws IOException { 541 return asWriter(supplier.getOutput()); 542 } 543 }; 544 } 545}