001/* 002 * Copyright (C) 2007 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 005 * in compliance with the License. You may obtain a copy of the License at 006 * 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, software distributed under the License 010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 011 * or implied. See the License for the specific language governing permissions and limitations under 012 * the License. 013 */ 014 015package com.google.common.io; 016 017import static com.google.common.base.Preconditions.checkNotNull; 018import static com.google.common.base.Preconditions.checkPositionIndexes; 019 020import com.google.common.annotations.Beta; 021import com.google.common.annotations.GwtIncompatible; 022import com.google.errorprone.annotations.CanIgnoreReturnValue; 023import java.io.Closeable; 024import java.io.EOFException; 025import java.io.IOException; 026import java.io.InputStream; 027import java.io.InputStreamReader; 028import java.io.OutputStream; 029import java.io.OutputStreamWriter; 030import java.io.Reader; 031import java.io.StringReader; 032import java.io.Writer; 033import java.nio.CharBuffer; 034import java.nio.charset.Charset; 035import java.util.ArrayList; 036import java.util.List; 037import org.checkerframework.checker.nullness.qual.Nullable; 038 039/** 040 * Provides utility methods for working with character streams. 041 * 042 * <p>All method parameters must be non-null unless documented otherwise. 043 * 044 * <p>Some of the methods in this class take arguments with a generic type of {@code Readable & 045 * Closeable}. A {@link java.io.Reader} implements both of those interfaces. Similarly for {@code 046 * Appendable & Closeable} and {@link java.io.Writer}. 047 * 048 * @author Chris Nokleberg 049 * @author Bin Zhu 050 * @author Colin Decker 051 * @since 1.0 052 */ 053@GwtIncompatible 054public final class CharStreams { 055 056 // 2K chars (4K bytes) 057 private static final int DEFAULT_BUF_SIZE = 0x800; 058 059 /** Creates a new {@code CharBuffer} for buffering reads or writes. */ 060 static CharBuffer createBuffer() { 061 return CharBuffer.allocate(DEFAULT_BUF_SIZE); 062 } 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 * @deprecated Use {@link CharSource#wrap(CharSequence)} instead. This method 073 * is scheduled for removal in Guava 18.0. 074 */ 075 @Deprecated 076 public static InputSupplier<StringReader> newReaderSupplier( 077 final String value) { 078 return asInputSupplier(CharSource.wrap(value)); 079 } 080 081 /** 082 * Returns a factory that will supply instances of {@link InputStreamReader}, 083 * using the given {@link InputStream} factory and character set. 084 * 085 * @param in the factory that will be used to open input streams 086 * @param charset the charset used to decode the input stream; see {@link 087 * Charsets} for helpful predefined constants 088 * @return the factory 089 * @deprecated Use {@link ByteSource#asCharSource(Charset)} instead. This 090 * method is scheduled for removal in Guava 18.0. 091 */ 092 @Deprecated 093 public static InputSupplier<InputStreamReader> newReaderSupplier( 094 final InputSupplier<? extends InputStream> in, final Charset charset) { 095 return asInputSupplier( 096 ByteStreams.asByteSource(in).asCharSource(charset)); 097 } 098 099 /** 100 * Returns a factory that will supply instances of {@link OutputStreamWriter}, 101 * using the given {@link OutputStream} factory and character set. 102 * 103 * @param out the factory that will be used to open output streams 104 * @param charset the charset used to encode the output stream; see {@link 105 * Charsets} for helpful predefined constants 106 * @return the factory 107 * @deprecated Use {@link ByteSink#asCharSink(Charset)} instead. This method 108 * is scheduled for removal in Guava 18.0. 109 */ 110 @Deprecated 111 public static OutputSupplier<OutputStreamWriter> newWriterSupplier( 112 final OutputSupplier<? extends OutputStream> out, final Charset charset) { 113 return asOutputSupplier( 114 ByteStreams.asByteSink(out).asCharSink(charset)); 115 } 116 117 /** 118 * Copies all characters between the {@link Readable} and {@link Appendable} objects. Does not 119 * close or flush either object. 120 * 121 * @param from the object to read from 122 * @param to the object to write to 123 * @return the number of characters copied 124 * @throws IOException if an I/O error occurs 125 */ 126 @CanIgnoreReturnValue 127 public static long copy(Readable from, Appendable to) throws IOException { 128 // The most common case is that from is a Reader (like InputStreamReader or StringReader) so 129 // take advantage of that. 130 if (from instanceof Reader) { 131 // optimize for common output types which are optimized to deal with char[] 132 if (to instanceof StringBuilder) { 133 return copyReaderToBuilder((Reader) from, (StringBuilder) to); 134 } else { 135 return copyReaderToWriter((Reader) from, asWriter(to)); 136 } 137 } else { 138 checkNotNull(from); 139 checkNotNull(to); 140 long total = 0; 141 CharBuffer buf = createBuffer(); 142 while (from.read(buf) != -1) { 143 buf.flip(); 144 to.append(buf); 145 total += buf.remaining(); 146 buf.clear(); 147 } 148 return total; 149 } 150 } 151 152 // TODO(lukes): consider allowing callers to pass in a buffer to use, some callers would be able 153 // to reuse buffers, others would be able to size them more appropriately than the constant 154 // defaults 155 156 /** 157 * Copies all characters between the {@link Reader} and {@link StringBuilder} objects. Does not 158 * close or flush the reader. 159 * 160 * <p>This is identical to {@link #copy(Readable, Appendable)} but optimized for these specific 161 * types. CharBuffer has poor performance when being written into or read out of so round tripping 162 * all the bytes through the buffer takes a long time. With these specialized types we can just 163 * use a char array. 164 * 165 * @param from the object to read from 166 * @param to the object to write to 167 * @return the number of characters copied 168 * @throws IOException if an I/O error occurs 169 */ 170 @CanIgnoreReturnValue 171 static long copyReaderToBuilder(Reader from, StringBuilder to) throws IOException { 172 checkNotNull(from); 173 checkNotNull(to); 174 char[] buf = new char[DEFAULT_BUF_SIZE]; 175 int nRead; 176 long total = 0; 177 while ((nRead = from.read(buf)) != -1) { 178 to.append(buf, 0, nRead); 179 total += nRead; 180 } 181 return total; 182 } 183 184 /** 185 * Copies all characters between the {@link Reader} and {@link Writer} objects. Does not close or 186 * flush the reader or writer. 187 * 188 * <p>This is identical to {@link #copy(Readable, Appendable)} but optimized for these specific 189 * types. CharBuffer has poor performance when being written into or read out of so round tripping 190 * all the bytes through the buffer takes a long time. With these specialized types we can just 191 * use a char array. 192 * 193 * @param from the object to read from 194 * @param to the object to write to 195 * @return the number of characters copied 196 * @throws IOException if an I/O error occurs 197 */ 198 @CanIgnoreReturnValue 199 static long copyReaderToWriter(Reader from, Writer to) throws IOException { 200 checkNotNull(from); 201 checkNotNull(to); 202 char[] buf = new char[DEFAULT_BUF_SIZE]; 203 int nRead; 204 long total = 0; 205 while ((nRead = from.read(buf)) != -1) { 206 to.write(buf, 0, nRead); 207 total += nRead; 208 } 209 return total; 210 } 211 212 /** 213 * Reads all characters from a {@link Readable} object into a {@link String}. Does not close the 214 * {@code Readable}. 215 * 216 * @param r the object to read from 217 * @return a string containing all the characters 218 * @throws IOException if an I/O error occurs 219 */ 220 public static String toString(Readable r) throws IOException { 221 return toStringBuilder(r).toString(); 222 } 223 224 /** 225 * Reads all characters from a {@link Readable} object into a new {@link StringBuilder} instance. 226 * Does not close the {@code Readable}. 227 * 228 * @param r the object to read from 229 * @return a {@link StringBuilder} containing all the characters 230 * @throws IOException if an I/O error occurs 231 */ 232 private static StringBuilder toStringBuilder(Readable r) throws IOException { 233 StringBuilder sb = new StringBuilder(); 234 if (r instanceof Reader) { 235 copyReaderToBuilder((Reader) r, sb); 236 } else { 237 copy(r, sb); 238 } 239 return sb; 240 } 241 242 /** 243 * Reads the first line from a {@link Readable} & {@link Closeable} object 244 * supplied by a factory. The line does not include line-termination 245 * characters, but does include other leading and trailing whitespace. 246 * 247 * @param supplier the factory to read from 248 * @return the first line, or null if the reader is empty 249 * @throws IOException if an I/O error occurs 250 * @deprecated Use {@link CharSource#readFirstLine()} instead. This method is 251 * scheduled for removal in Guava 18.0. 252 */ 253 @Deprecated 254 public static <R extends Readable & Closeable> String readFirstLine( 255 InputSupplier<R> supplier) throws IOException { 256 return asCharSource(supplier).readFirstLine(); 257 } 258 259 /** 260 * Reads all of the lines from a {@link Readable} & {@link Closeable} object 261 * supplied by a factory. The lines do not include line-termination 262 * characters, but do include other leading and trailing whitespace. 263 * 264 * @param supplier the factory to read from 265 * @return a mutable {@link List} containing all the lines 266 * @throws IOException if an I/O error occurs 267 * @deprecated Use {@link CharSource#readLines()} instead, but note that it 268 * returns an {@code ImmutableList}. This method is scheduled for removal 269 * in Guava 18.0. 270 */ 271 @Deprecated 272 public static <R extends Readable & Closeable> List<String> readLines( 273 InputSupplier<R> supplier) throws IOException { 274 Closer closer = Closer.create(); 275 try { 276 R r = closer.register(supplier.getInput()); 277 return readLines(r); 278 } catch (Throwable e) { 279 throw closer.rethrow(e); 280 } finally { 281 closer.close(); 282 } 283 } 284 285 /** 286 * Reads all of the lines from a {@link Readable} object. The lines do not include 287 * line-termination characters, but do include other leading and trailing whitespace. 288 * 289 * <p>Does not close the {@code Readable}. If reading files or resources you should use the {@link 290 * Files#readLines} and {@link Resources#readLines} methods. 291 * 292 * @param r the object to read from 293 * @return a mutable {@link List} containing all the lines 294 * @throws IOException if an I/O error occurs 295 */ 296 @Beta 297 public static List<String> readLines(Readable r) throws IOException { 298 List<String> result = new ArrayList<>(); 299 LineReader lineReader = new LineReader(r); 300 String line; 301 while ((line = lineReader.readLine()) != null) { 302 result.add(line); 303 } 304 return result; 305 } 306 307 /** 308 * Streams lines from a {@link Readable} object, stopping when the processor returns {@code false} 309 * or all lines have been read and returning the result produced by the processor. Does not close 310 * {@code readable}. Note that this method may not fully consume the contents of {@code readable} 311 * if the processor stops processing early. 312 * 313 * @throws IOException if an I/O error occurs 314 * @since 14.0 315 */ 316 @Beta 317 @CanIgnoreReturnValue // some processors won't return a useful result 318 public static <T> T readLines(Readable readable, LineProcessor<T> processor) throws IOException { 319 checkNotNull(readable); 320 checkNotNull(processor); 321 322 LineReader lineReader = new LineReader(readable); 323 String line; 324 while ((line = lineReader.readLine()) != null) { 325 if (!processor.processLine(line)) { 326 break; 327 } 328 } 329 return processor.getResult(); 330 } 331 332 /** 333 * Reads and discards data from the given {@code Readable} until the end of the stream is reached. 334 * Returns the total number of chars read. Does not close the stream. 335 * 336 * @since 20.0 337 */ 338 @Beta 339 @CanIgnoreReturnValue 340 public static long exhaust(Readable readable) throws IOException { 341 long total = 0; 342 long read; 343 CharBuffer buf = createBuffer(); 344 while ((read = readable.read(buf)) != -1) { 345 total += read; 346 buf.clear(); 347 } 348 return total; 349 } 350 351 /** 352 * Discards {@code n} characters of data from the reader. This method will block until the full 353 * amount has been skipped. Does not close the reader. 354 * 355 * @param reader the reader to read from 356 * @param n the number of characters to skip 357 * @throws EOFException if this stream reaches the end before skipping all the characters 358 * @throws IOException if an I/O error occurs 359 */ 360 @Beta 361 public static void skipFully(Reader reader, long n) throws IOException { 362 checkNotNull(reader); 363 while (n > 0) { 364 long amt = reader.skip(n); 365 if (amt == 0) { 366 throw new EOFException(); 367 } 368 n -= amt; 369 } 370 } 371 372 /** 373 * Returns a {@link Writer} that simply discards written chars. 374 * 375 * @since 15.0 376 */ 377 @Beta 378 public static Writer nullWriter() { 379 return NullWriter.INSTANCE; 380 } 381 382 private static final class NullWriter extends Writer { 383 384 private static final NullWriter INSTANCE = new NullWriter(); 385 386 @Override 387 public void write(int c) {} 388 389 @Override 390 public void write(char[] cbuf) { 391 checkNotNull(cbuf); 392 } 393 394 @Override 395 public void write(char[] cbuf, int off, int len) { 396 checkPositionIndexes(off, off + len, cbuf.length); 397 } 398 399 @Override 400 public void write(String str) { 401 checkNotNull(str); 402 } 403 404 @Override 405 public void write(String str, int off, int len) { 406 checkPositionIndexes(off, off + len, str.length()); 407 } 408 409 @Override 410 public Writer append(@Nullable CharSequence csq) { 411 return this; 412 } 413 414 @Override 415 public Writer append(@Nullable CharSequence csq, int start, int end) { 416 checkPositionIndexes(start, end, csq == null ? "null".length() : csq.length()); 417 return this; 418 } 419 420 @Override 421 public Writer append(char c) { 422 return this; 423 } 424 425 @Override 426 public void flush() {} 427 428 @Override 429 public void close() {} 430 431 @Override 432 public String toString() { 433 return "CharStreams.nullWriter()"; 434 } 435 } 436 437 /** 438 * Returns a Writer that sends all output to the given {@link Appendable} target. Closing the 439 * writer will close the target if it is {@link Closeable}, and flushing the writer will flush the 440 * target if it is {@link java.io.Flushable}. 441 * 442 * @param target the object to which output will be sent 443 * @return a new Writer object, unless target is a Writer, in which case the target is returned 444 */ 445 @Beta 446 public static Writer asWriter(Appendable target) { 447 if (target instanceof Writer) { 448 return (Writer) target; 449 } 450 return new AppendableWriter(target); 451 } 452 453 // TODO(cgdecker): Remove these once Input/OutputSupplier methods are removed 454 455 static Reader asReader(final Readable readable) { 456 checkNotNull(readable); 457 if (readable instanceof Reader) { 458 return (Reader) readable; 459 } 460 return new Reader() { 461 @Override 462 public int read(char[] cbuf, int off, int len) throws IOException { 463 return read(CharBuffer.wrap(cbuf, off, len)); 464 } 465 466 @Override 467 public int read(CharBuffer target) throws IOException { 468 return readable.read(target); 469 } 470 471 @Override 472 public void close() throws IOException { 473 if (readable instanceof Closeable) { 474 ((Closeable) readable).close(); 475 } 476 } 477 }; 478 } 479 480 /** 481 * Returns a view of the given {@code Readable} supplier as a 482 * {@code CharSource}. 483 * 484 * <p>This method is a temporary method provided for easing migration from 485 * suppliers to sources and sinks. 486 * 487 * @since 15.0 488 * @deprecated Convert all {@code InputSupplier<? extends Readable>} 489 * implementations to extend {@link CharSource} or provide a method for 490 * viewing the object as a {@code CharSource}. This method is scheduled 491 * for removal in Guava 18.0. 492 */ 493 @Deprecated 494 public static CharSource asCharSource( 495 final InputSupplier<? extends Readable> supplier) { 496 checkNotNull(supplier); 497 return new CharSource() { 498 @Override 499 public Reader openStream() throws IOException { 500 return asReader(supplier.getInput()); 501 } 502 503 @Override 504 public String toString() { 505 return "CharStreams.asCharSource(" + supplier + ")"; 506 } 507 }; 508 } 509 510 /** 511 * Returns a view of the given {@code Appendable} supplier as a 512 * {@code CharSink}. 513 * 514 * <p>This method is a temporary method provided for easing migration from 515 * suppliers to sources and sinks. 516 * 517 * @since 15.0 518 * @deprecated Convert all {@code OutputSupplier<? extends Appendable>} 519 * implementations to extend {@link CharSink} or provide a method for 520 * viewing the object as a {@code CharSink}. This method is scheduled 521 * for removal in Guava 18.0. 522 */ 523 @Deprecated 524 public static CharSink asCharSink( 525 final OutputSupplier<? extends Appendable> supplier) { 526 checkNotNull(supplier); 527 return new CharSink() { 528 @Override 529 public Writer openStream() throws IOException { 530 return asWriter(supplier.getOutput()); 531 } 532 533 @Override 534 public String toString() { 535 return "CharStreams.asCharSink(" + supplier + ")"; 536 } 537 }; 538 } 539 540 @SuppressWarnings("unchecked") // used internally where known to be safe 541 static <R extends Reader> InputSupplier<R> asInputSupplier( 542 CharSource source) { 543 return (InputSupplier) checkNotNull(source); 544 } 545 546 @SuppressWarnings("unchecked") // used internally where known to be safe 547 static <W extends Writer> OutputSupplier<W> asOutputSupplier( 548 CharSink sink) { 549 return (OutputSupplier) checkNotNull(sink); 550 } 551}