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