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 17package com.google.common.io; 18 19import static com.google.common.base.Preconditions.checkNotNull; 20import static com.google.common.base.Preconditions.checkPositionIndexes; 21 22import com.google.common.annotations.Beta; 23import com.google.common.base.Charsets; 24import com.google.common.base.Function; 25import com.google.common.collect.Iterables; 26 27import java.io.Closeable; 28import java.io.EOFException; 29import java.io.IOException; 30import java.io.InputStream; 31import java.io.InputStreamReader; 32import java.io.OutputStream; 33import java.io.OutputStreamWriter; 34import java.io.Reader; 35import java.io.StringReader; 36import java.io.Writer; 37import java.nio.CharBuffer; 38import java.nio.charset.Charset; 39import java.util.ArrayList; 40import java.util.Arrays; 41import java.util.List; 42 43/** 44 * Provides utility methods for working with character streams. 45 * 46 * <p>All method parameters must be non-null unless documented otherwise. 47 * 48 * <p>Some of the methods in this class take arguments with a generic type of 49 * {@code Readable & Closeable}. A {@link java.io.Reader} implements both of 50 * those interfaces. Similarly for {@code Appendable & Closeable} and 51 * {@link java.io.Writer}. 52 * 53 * @author Chris Nokleberg 54 * @author Bin Zhu 55 * @author Colin Decker 56 * @since 1.0 57 */ 58@Beta 59public final class CharStreams { 60 private static final int BUF_SIZE = 0x800; // 2K chars (4K bytes) 61 62 private CharStreams() {} 63 64 /** 65 * Returns a factory that will supply instances of {@link StringReader} that 66 * read a string value. 67 * 68 * @param value the string to read 69 * @return the factory 70 * @deprecated Use {@link CharSource#wrap(CharSequence)} instead. This method 71 * is scheduled for removal in Guava 18.0. 72 */ 73 @Deprecated 74 public static InputSupplier<StringReader> newReaderSupplier( 75 final String value) { 76 return asInputSupplier(CharSource.wrap(value)); 77 } 78 79 /** 80 * Returns a {@link CharSource} that reads the given string value. 81 * 82 * @since 14.0 83 * @deprecated Use {@link CharSource#wrap(CharSequence)} instead. This method 84 * is scheduled to be removed in Guava 16.0. 85 */ 86 @Deprecated 87 public static CharSource asCharSource(String string) { 88 return CharSource.wrap(string); 89 } 90 91 /** 92 * Returns a factory that will supply instances of {@link InputStreamReader}, 93 * using the given {@link InputStream} factory and character set. 94 * 95 * @param in the factory that will be used to open input streams 96 * @param charset the charset used to decode the input stream; see {@link 97 * Charsets} for helpful predefined constants 98 * @return the factory 99 * @deprecated Use {@link ByteSource#asCharSource(Charset)} instead. This 100 * method is scheduled for removal in Guava 18.0. 101 */ 102 @Deprecated 103 public static InputSupplier<InputStreamReader> newReaderSupplier( 104 final InputSupplier<? extends InputStream> in, final Charset charset) { 105 return asInputSupplier( 106 ByteStreams.asByteSource(in).asCharSource(charset)); 107 } 108 109 /** 110 * Returns a factory that will supply instances of {@link OutputStreamWriter}, 111 * using the given {@link OutputStream} factory and character set. 112 * 113 * @param out the factory that will be used to open output streams 114 * @param charset the charset used to encode the output stream; see {@link 115 * Charsets} for helpful predefined constants 116 * @return the factory 117 * @deprecated Use {@link ByteSink#asCharSink(Charset)} instead. This method 118 * is scheduled for removal in Guava 18.0. 119 */ 120 @Deprecated 121 public static OutputSupplier<OutputStreamWriter> newWriterSupplier( 122 final OutputSupplier<? extends OutputStream> out, final Charset charset) { 123 return asOutputSupplier( 124 ByteStreams.asByteSink(out).asCharSink(charset)); 125 } 126 127 /** 128 * Writes a character sequence (such as a string) to an appendable 129 * object from the given supplier. 130 * 131 * @param from the character sequence to write 132 * @param to the output supplier 133 * @throws IOException if an I/O error occurs 134 * @deprecated Use {@link CharSink#write(CharSequence)} instead. This method 135 * is scheduled for removal in Guava 18.0. 136 */ 137 @Deprecated 138 public static <W extends Appendable & Closeable> void write(CharSequence from, 139 OutputSupplier<W> to) throws IOException { 140 asCharSink(to).write(from); 141 } 142 143 /** 144 * Opens {@link Readable} and {@link Appendable} objects from the 145 * given factories, copies all characters between the two, and closes 146 * them. 147 * 148 * @param from the input factory 149 * @param to the output factory 150 * @return the number of characters copied 151 * @throws IOException if an I/O error occurs 152 * @deprecated Use {@link CharSource#copyTo(CharSink)} instead. This method is 153 * scheduled for removal in Guava 18.0. 154 */ 155 @Deprecated 156 public static <R extends Readable & Closeable, 157 W extends Appendable & Closeable> long copy(InputSupplier<R> from, 158 OutputSupplier<W> to) throws IOException { 159 return asCharSource(from).copyTo(asCharSink(to)); 160 } 161 162 /** 163 * Opens a {@link Readable} object from the supplier, copies all characters 164 * to the {@link Appendable} object, and closes the input. Does not close 165 * or flush the output. 166 * 167 * @param from the input factory 168 * @param to the object to write to 169 * @return the number of characters copied 170 * @throws IOException if an I/O error occurs 171 * @deprecated Use {@link CharSource#copyTo(Appendable)} instead. This method 172 * is scheduled for removal in Guava 18.0. 173 */ 174 @Deprecated 175 public static <R extends Readable & Closeable> long copy( 176 InputSupplier<R> from, Appendable to) throws IOException { 177 return asCharSource(from).copyTo(to); 178 } 179 180 /** 181 * Copies all characters between the {@link Readable} and {@link Appendable} 182 * objects. Does not close or flush either object. 183 * 184 * @param from the object to read from 185 * @param to the object to write to 186 * @return the number of characters copied 187 * @throws IOException if an I/O error occurs 188 */ 189 public static long copy(Readable from, Appendable to) throws IOException { 190 checkNotNull(from); 191 checkNotNull(to); 192 CharBuffer buf = CharBuffer.allocate(BUF_SIZE); 193 long total = 0; 194 while (from.read(buf) != -1) { 195 buf.flip(); 196 to.append(buf); 197 total += buf.remaining(); 198 buf.clear(); 199 } 200 return total; 201 } 202 203 /** 204 * Reads all characters from a {@link Readable} object into a {@link String}. 205 * Does not close the {@code Readable}. 206 * 207 * @param r the object to read from 208 * @return a string containing all the characters 209 * @throws IOException if an I/O error occurs 210 */ 211 public static String toString(Readable r) throws IOException { 212 return toStringBuilder(r).toString(); 213 } 214 215 /** 216 * Returns the characters from a {@link Readable} & {@link Closeable} object 217 * supplied by a factory as a {@link String}. 218 * 219 * @param supplier the factory to read from 220 * @return a string containing all the characters 221 * @throws IOException if an I/O error occurs 222 * @deprecated Use {@link CharSource#read()} instead. This method is 223 * scheduled for removal in Guava 18.0. 224 */ 225 @Deprecated 226 public static <R extends Readable & Closeable> String toString( 227 InputSupplier<R> supplier) throws IOException { 228 return asCharSource(supplier).read(); 229 } 230 231 /** 232 * Reads all characters from a {@link Readable} object into a new 233 * {@link StringBuilder} instance. Does not close the {@code Readable}. 234 * 235 * @param r the object to read from 236 * @return a {@link StringBuilder} containing all the characters 237 * @throws IOException if an I/O error occurs 238 */ 239 private static StringBuilder toStringBuilder(Readable r) throws IOException { 240 StringBuilder sb = new StringBuilder(); 241 copy(r, sb); 242 return sb; 243 } 244 245 /** 246 * Reads the first line from a {@link Readable} & {@link Closeable} object 247 * supplied by a factory. The line does not include line-termination 248 * characters, but does include other leading and trailing whitespace. 249 * 250 * @param supplier the factory to read from 251 * @return the first line, or null if the reader is empty 252 * @throws IOException if an I/O error occurs 253 * @deprecated Use {@link CharSource#readFirstLine()} instead. This method is 254 * scheduled for removal in Guava 18.0. 255 */ 256 @Deprecated 257 public static <R extends Readable & Closeable> String readFirstLine( 258 InputSupplier<R> supplier) throws IOException { 259 return asCharSource(supplier).readFirstLine(); 260 } 261 262 /** 263 * Reads all of the lines from a {@link Readable} & {@link Closeable} object 264 * supplied by a factory. The lines do not include line-termination 265 * characters, but do include other leading and trailing whitespace. 266 * 267 * @param supplier the factory to read from 268 * @return a mutable {@link List} containing all the lines 269 * @throws IOException if an I/O error occurs 270 * @deprecated Use {@link CharSource#readLines()} instead, but note that it 271 * returns an {@code ImmutableList}. This method is scheduled for removal 272 * in Guava 18.0. 273 */ 274 @Deprecated 275 public static <R extends Readable & Closeable> List<String> readLines( 276 InputSupplier<R> supplier) throws IOException { 277 Closer closer = Closer.create(); 278 try { 279 R r = closer.register(supplier.getInput()); 280 return readLines(r); 281 } catch (Throwable e) { 282 throw closer.rethrow(e); 283 } finally { 284 closer.close(); 285 } 286 } 287 288 /** 289 * Reads all of the lines from a {@link Readable} object. The lines do 290 * not include line-termination characters, but do include other 291 * leading and trailing whitespace. 292 * 293 * <p>Does not close the {@code Readable}. If reading files or resources you 294 * should use the {@link Files#readLines} and {@link Resources#readLines} 295 * methods. 296 * 297 * @param r the object to read from 298 * @return a mutable {@link List} containing all the lines 299 * @throws IOException if an I/O error occurs 300 */ 301 public static List<String> readLines(Readable r) throws IOException { 302 List<String> result = new ArrayList<String>(); 303 LineReader lineReader = new LineReader(r); 304 String line; 305 while ((line = lineReader.readLine()) != null) { 306 result.add(line); 307 } 308 return result; 309 } 310 311 /** 312 * Streams lines from a {@link Readable} object, stopping when the processor 313 * returns {@code false} or all lines have been read and returning the result 314 * produced by the processor. Does not close {@code readable}. Note that this 315 * method may not fully consume the contents of {@code readable} if the 316 * processor stops processing early. 317 * 318 * @throws IOException if an I/O error occurs 319 * @since 14.0 320 */ 321 public static <T> T readLines( 322 Readable readable, LineProcessor<T> processor) throws IOException { 323 checkNotNull(readable); 324 checkNotNull(processor); 325 326 LineReader lineReader = new LineReader(readable); 327 String line; 328 while ((line = lineReader.readLine()) != null) { 329 if (!processor.processLine(line)) { 330 break; 331 } 332 } 333 return processor.getResult(); 334 } 335 336 /** 337 * Streams lines from a {@link Readable} and {@link Closeable} object 338 * supplied by a factory, stopping when our callback returns false, or we 339 * have read all of the lines. 340 * 341 * @param supplier the factory to read from 342 * @param callback the LineProcessor to use to handle the lines 343 * @return the output of processing the lines 344 * @throws IOException if an I/O error occurs 345 * @deprecated Use {@link CharSource#readLines(LineProcessor)} instead. This 346 * method is scheduled for removal in Guava 18.0. 347 */ 348 @Deprecated 349 public static <R extends Readable & Closeable, T> T readLines( 350 InputSupplier<R> supplier, LineProcessor<T> callback) throws IOException { 351 checkNotNull(supplier); 352 checkNotNull(callback); 353 354 Closer closer = Closer.create(); 355 try { 356 R r = closer.register(supplier.getInput()); 357 return readLines(r, callback); 358 } catch (Throwable e) { 359 throw closer.rethrow(e); 360 } finally { 361 closer.close(); 362 } 363 } 364 365 /** 366 * Joins multiple {@link Reader} suppliers into a single supplier. 367 * Reader returned from the supplier will contain the concatenated data 368 * from the readers of the underlying suppliers. 369 * 370 * <p>Reading from the joined reader will throw a {@link NullPointerException} 371 * if any of the suppliers are null or return null. 372 * 373 * <p>Only one underlying reader will be open at a time. Closing the 374 * joined reader will close the open underlying reader. 375 * 376 * @param suppliers the suppliers to concatenate 377 * @return a supplier that will return a reader containing the concatenated 378 * data 379 * @deprecated Use {@link CharSource#concat(Iterable)} instead. This method 380 * is scheduled for removal in Guava 18.0. 381 */ 382 @Deprecated 383 public static InputSupplier<Reader> join( 384 final Iterable<? extends InputSupplier<? extends Reader>> suppliers) { 385 checkNotNull(suppliers); 386 Iterable<CharSource> sources = Iterables.transform(suppliers, 387 new Function<InputSupplier<? extends Reader>, CharSource>() { 388 @Override 389 public CharSource apply(InputSupplier<? extends Reader> input) { 390 return asCharSource(input); 391 } 392 }); 393 return asInputSupplier(CharSource.concat(sources)); 394 } 395 396 /** 397 * Varargs form of {@link #join(Iterable)}. 398 * 399 * @deprecated Use {@link CharSource#concat(CharSource[])} instead. This 400 * method is scheduled for removal in Guava 18.0. 401 */ 402 @Deprecated 403 @SuppressWarnings("unchecked") // suppress "possible heap pollution" warning in JDK7 404 public static InputSupplier<Reader> join( 405 InputSupplier<? extends Reader>... suppliers) { 406 return join(Arrays.asList(suppliers)); 407 } 408 409 /** 410 * Discards {@code n} characters of data from the reader. This method 411 * will block until the full amount has been skipped. Does not close the 412 * reader. 413 * 414 * @param reader the reader to read from 415 * @param n the number of characters to skip 416 * @throws EOFException if this stream reaches the end before skipping all 417 * the characters 418 * @throws IOException if an I/O error occurs 419 */ 420 public static void skipFully(Reader reader, long n) throws IOException { 421 checkNotNull(reader); 422 while (n > 0) { 423 long amt = reader.skip(n); 424 if (amt == 0) { 425 // force a blocking read 426 if (reader.read() == -1) { 427 throw new EOFException(); 428 } 429 n--; 430 } else { 431 n -= amt; 432 } 433 } 434 } 435 436 /** 437 * Returns a {@link Writer} that simply discards written chars. 438 * 439 * @since 15.0 440 */ 441 public static Writer nullWriter() { 442 return NullWriter.INSTANCE; 443 } 444 445 private static final class NullWriter extends Writer { 446 447 private static final NullWriter INSTANCE = new NullWriter(); 448 449 @Override 450 public void write(int c) { 451 } 452 453 @Override 454 public void write(char[] cbuf) { 455 checkNotNull(cbuf); 456 } 457 458 @Override 459 public void write(char[] cbuf, int off, int len) { 460 checkPositionIndexes(off, off + len, cbuf.length); 461 } 462 463 @Override 464 public void write(String str) { 465 checkNotNull(str); 466 } 467 468 @Override 469 public void write(String str, int off, int len) { 470 checkPositionIndexes(off, off + len, str.length()); 471 } 472 473 @Override 474 public Writer append(CharSequence csq) { 475 checkNotNull(csq); 476 return this; 477 } 478 479 @Override 480 public Writer append(CharSequence csq, int start, int end) { 481 checkPositionIndexes(start, end, csq.length()); 482 return this; 483 } 484 485 @Override 486 public Writer append(char c) { 487 return this; 488 } 489 490 @Override 491 public void flush() { 492 } 493 494 @Override 495 public void close() { 496 } 497 498 @Override 499 public String toString() { 500 return "CharStreams.nullWriter()"; 501 } 502 } 503 504 /** 505 * Returns a Writer that sends all output to the given {@link Appendable} 506 * target. Closing the writer will close the target if it is {@link 507 * Closeable}, and flushing the writer will flush the target if it is {@link 508 * java.io.Flushable}. 509 * 510 * @param target the object to which output will be sent 511 * @return a new Writer object, unless target is a Writer, in which case the 512 * target is returned 513 */ 514 public static Writer asWriter(Appendable target) { 515 if (target instanceof Writer) { 516 return (Writer) target; 517 } 518 return new AppendableWriter(target); 519 } 520 521 // TODO(user): Remove these once Input/OutputSupplier methods are removed 522 523 static Reader asReader(final Readable readable) { 524 checkNotNull(readable); 525 if (readable instanceof Reader) { 526 return (Reader) readable; 527 } 528 return new Reader() { 529 @Override 530 public int read(char[] cbuf, int off, int len) throws IOException { 531 return read(CharBuffer.wrap(cbuf, off, len)); 532 } 533 534 @Override 535 public int read(CharBuffer target) throws IOException { 536 return readable.read(target); 537 } 538 539 @Override 540 public void close() throws IOException { 541 if (readable instanceof Closeable) { 542 ((Closeable) readable).close(); 543 } 544 } 545 }; 546 } 547 548 /** 549 * Returns a view of the given {@code Readable} supplier as a 550 * {@code CharSource}. 551 * 552 * <p>This method is a temporary method provided for easing migration from 553 * suppliers to sources and sinks. 554 * 555 * @since 15.0 556 * @deprecated Convert all {@code InputSupplier<? extends Readable>} 557 * implementations to extend {@link CharSource} or provide a method for 558 * viewing the object as a {@code CharSource}. This method is scheduled 559 * for removal in Guava 18.0. 560 */ 561 @Deprecated 562 public static CharSource asCharSource( 563 final InputSupplier<? extends Readable> supplier) { 564 checkNotNull(supplier); 565 return new CharSource() { 566 @Override 567 public Reader openStream() throws IOException { 568 return asReader(supplier.getInput()); 569 } 570 571 @Override 572 public String toString() { 573 return "CharStreams.asCharSource(" + supplier + ")"; 574 } 575 }; 576 } 577 578 /** 579 * Returns a view of the given {@code Appendable} supplier as a 580 * {@code CharSink}. 581 * 582 * <p>This method is a temporary method provided for easing migration from 583 * suppliers to sources and sinks. 584 * 585 * @since 15.0 586 * @deprecated Convert all {@code OutputSupplier<? extends Appendable>} 587 * implementations to extend {@link CharSink} or provide a method for 588 * viewing the object as a {@code CharSink}. This method is scheduled 589 * for removal in Guava 18.0. 590 */ 591 @Deprecated 592 public static CharSink asCharSink( 593 final OutputSupplier<? extends Appendable> supplier) { 594 checkNotNull(supplier); 595 return new CharSink() { 596 @Override 597 public Writer openStream() throws IOException { 598 return asWriter(supplier.getOutput()); 599 } 600 601 @Override 602 public String toString() { 603 return "CharStreams.asCharSink(" + supplier + ")"; 604 } 605 }; 606 } 607 608 @SuppressWarnings("unchecked") // used internally where known to be safe 609 static <R extends Reader> InputSupplier<R> asInputSupplier( 610 CharSource source) { 611 return (InputSupplier) checkNotNull(source); 612 } 613 614 @SuppressWarnings("unchecked") // used internally where known to be safe 615 static <W extends Writer> OutputSupplier<W> asOutputSupplier( 616 CharSink sink) { 617 return (OutputSupplier) checkNotNull(sink); 618 } 619} 620