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