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 017 package com.google.common.io; 018 019 import com.google.common.annotations.Beta; 020 import com.google.common.base.Charsets; 021 import com.google.common.base.Preconditions; 022 023 import java.io.Closeable; 024 import java.io.EOFException; 025 import java.io.IOException; 026 import java.io.InputStream; 027 import java.io.InputStreamReader; 028 import java.io.OutputStream; 029 import java.io.OutputStreamWriter; 030 import java.io.Reader; 031 import java.io.StringReader; 032 import java.io.Writer; 033 import java.nio.CharBuffer; 034 import java.nio.charset.Charset; 035 import java.util.ArrayList; 036 import java.util.Arrays; 037 import java.util.List; 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 045 * {@code Readable & Closeable}. A {@link java.io.Reader} implements both of 046 * those interfaces. Similarly for {@code Appendable & Closeable} and 047 * {@link java.io.Writer}. 048 * 049 * @author Chris Nokleberg 050 * @author Bin Zhu 051 * @since 1.0 052 */ 053 @Beta 054 public final class CharStreams { 055 private static final int BUF_SIZE = 0x800; // 2K chars (4K bytes) 056 057 private CharStreams() {} 058 059 /** 060 * Returns a factory that will supply instances of {@link StringReader} that 061 * read a string value. 062 * 063 * @param value the string to read 064 * @return the factory 065 */ 066 public static InputSupplier<StringReader> newReaderSupplier( 067 final String value) { 068 Preconditions.checkNotNull(value); 069 return new InputSupplier<StringReader>() { 070 @Override 071 public StringReader getInput() { 072 return new StringReader(value); 073 } 074 }; 075 } 076 077 /** 078 * Returns a factory that will supply instances of {@link InputStreamReader}, 079 * using the given {@link InputStream} factory and character set. 080 * 081 * @param in the factory that will be used to open input streams 082 * @param charset the charset used to decode the input stream; see {@link 083 * Charsets} for helpful predefined constants 084 * @return the factory 085 */ 086 public static InputSupplier<InputStreamReader> newReaderSupplier( 087 final InputSupplier<? extends InputStream> in, final Charset charset) { 088 Preconditions.checkNotNull(in); 089 Preconditions.checkNotNull(charset); 090 return new InputSupplier<InputStreamReader>() { 091 @Override 092 public InputStreamReader getInput() throws IOException { 093 return new InputStreamReader(in.getInput(), charset); 094 } 095 }; 096 } 097 098 /** 099 * Returns a factory that will supply instances of {@link OutputStreamWriter}, 100 * using the given {@link OutputStream} factory and character set. 101 * 102 * @param out the factory that will be used to open output streams 103 * @param charset the charset used to encode the output stream; see {@link 104 * Charsets} for helpful predefined constants 105 * @return the factory 106 */ 107 public static OutputSupplier<OutputStreamWriter> newWriterSupplier( 108 final OutputSupplier<? extends OutputStream> out, final Charset charset) { 109 Preconditions.checkNotNull(out); 110 Preconditions.checkNotNull(charset); 111 return new OutputSupplier<OutputStreamWriter>() { 112 @Override 113 public OutputStreamWriter getOutput() throws IOException { 114 return new OutputStreamWriter(out.getOutput(), charset); 115 } 116 }; 117 } 118 119 /** 120 * Writes a character sequence (such as a string) to an appendable 121 * object from the given supplier. 122 * 123 * @param from the character sequence to write 124 * @param to the output supplier 125 * @throws IOException if an I/O error occurs 126 */ 127 public static <W extends Appendable & Closeable> void write(CharSequence from, 128 OutputSupplier<W> to) throws IOException { 129 Preconditions.checkNotNull(from); 130 boolean threw = true; 131 W out = to.getOutput(); 132 try { 133 out.append(from); 134 threw = false; 135 } finally { 136 Closeables.close(out, threw); 137 } 138 } 139 140 /** 141 * Opens {@link Readable} and {@link Appendable} objects from the 142 * given factories, copies all characters between the two, and closes 143 * them. 144 * 145 * @param from the input factory 146 * @param to the output factory 147 * @return the number of characters copied 148 * @throws IOException if an I/O error occurs 149 */ 150 public static <R extends Readable & Closeable, 151 W extends Appendable & Closeable> long copy(InputSupplier<R> from, 152 OutputSupplier<W> to) throws IOException { 153 int successfulOps = 0; 154 R in = from.getInput(); 155 try { 156 W out = to.getOutput(); 157 try { 158 long count = copy(in, out); 159 successfulOps++; 160 return count; 161 } finally { 162 Closeables.close(out, successfulOps < 1); 163 successfulOps++; 164 } 165 } finally { 166 Closeables.close(in, successfulOps < 2); 167 } 168 } 169 170 /** 171 * Opens a {@link Readable} object from the supplier, copies all characters 172 * to the {@link Appendable} object, and closes the input. Does not close 173 * or flush the output. 174 * 175 * @param from the input factory 176 * @param to the object to write to 177 * @return the number of characters copied 178 * @throws IOException if an I/O error occurs 179 */ 180 public static <R extends Readable & Closeable> long copy( 181 InputSupplier<R> from, Appendable to) throws IOException { 182 boolean threw = true; 183 R in = from.getInput(); 184 try { 185 long count = copy(in, to); 186 threw = false; 187 return count; 188 } finally { 189 Closeables.close(in, threw); 190 } 191 } 192 193 /** 194 * Copies all characters between the {@link Readable} and {@link Appendable} 195 * objects. Does not close or flush either object. 196 * 197 * @param from the object to read from 198 * @param to the object to write to 199 * @return the number of characters copied 200 * @throws IOException if an I/O error occurs 201 */ 202 public static long copy(Readable from, Appendable to) throws IOException { 203 CharBuffer buf = CharBuffer.allocate(BUF_SIZE); 204 long total = 0; 205 while (from.read(buf) != -1) { 206 buf.flip(); 207 to.append(buf); 208 total += buf.remaining(); 209 buf.clear(); 210 } 211 return total; 212 } 213 214 /** 215 * Reads all characters from a {@link Readable} object into a {@link String}. 216 * Does not close the {@code Readable}. 217 * 218 * @param r the object to read from 219 * @return a string containing all the characters 220 * @throws IOException if an I/O error occurs 221 */ 222 public static String toString(Readable r) throws IOException { 223 return toStringBuilder(r).toString(); 224 } 225 226 /** 227 * Returns the characters from a {@link Readable} & {@link Closeable} object 228 * supplied by a factory as a {@link String}. 229 * 230 * @param supplier the factory to read from 231 * @return a string containing all the characters 232 * @throws IOException if an I/O error occurs 233 */ 234 public static <R extends Readable & Closeable> String toString( 235 InputSupplier<R> supplier) throws IOException { 236 return toStringBuilder(supplier).toString(); 237 } 238 239 /** 240 * Reads all characters from a {@link Readable} object into a new 241 * {@link StringBuilder} instance. Does not close the {@code Readable}. 242 * 243 * @param r the object to read from 244 * @return a {@link StringBuilder} containing all the characters 245 * @throws IOException if an I/O error occurs 246 */ 247 private static StringBuilder toStringBuilder(Readable r) throws IOException { 248 StringBuilder sb = new StringBuilder(); 249 copy(r, sb); 250 return sb; 251 } 252 253 /** 254 * Returns the characters from a {@link Readable} & {@link Closeable} object 255 * supplied by a factory as a new {@link StringBuilder} instance. 256 * 257 * @param supplier the factory to read from 258 * @throws IOException if an I/O error occurs 259 */ 260 private static <R extends Readable & Closeable> StringBuilder toStringBuilder( 261 InputSupplier<R> supplier) throws IOException { 262 boolean threw = true; 263 R r = supplier.getInput(); 264 try { 265 StringBuilder result = toStringBuilder(r); 266 threw = false; 267 return result; 268 } finally { 269 Closeables.close(r, threw); 270 } 271 } 272 273 /** 274 * Reads the first line from a {@link Readable} & {@link Closeable} object 275 * supplied by a factory. The line does not include line-termination 276 * characters, but does include other leading and trailing whitespace. 277 * 278 * @param supplier the factory to read from 279 * @return the first line, or null if the reader is empty 280 * @throws IOException if an I/O error occurs 281 */ 282 public static <R extends Readable & Closeable> String readFirstLine( 283 InputSupplier<R> supplier) throws IOException { 284 boolean threw = true; 285 R r = supplier.getInput(); 286 try { 287 String line = new LineReader(r).readLine(); 288 threw = false; 289 return line; 290 } finally { 291 Closeables.close(r, threw); 292 } 293 } 294 295 /** 296 * Reads all of the lines from a {@link Readable} & {@link Closeable} object 297 * supplied by a factory. The lines do not include line-termination 298 * characters, but do include other leading and trailing whitespace. 299 * 300 * @param supplier the factory to read from 301 * @return a mutable {@link List} containing all the lines 302 * @throws IOException if an I/O error occurs 303 */ 304 public static <R extends Readable & Closeable> List<String> readLines( 305 InputSupplier<R> supplier) throws IOException { 306 boolean threw = true; 307 R r = supplier.getInput(); 308 try { 309 List<String> result = readLines(r); 310 threw = false; 311 return result; 312 } finally { 313 Closeables.close(r, threw); 314 } 315 } 316 317 /** 318 * Reads all of the lines from a {@link Readable} object. The lines do 319 * not include line-termination characters, but do include other 320 * leading and trailing whitespace. 321 * 322 * <p>Does not close the {@code Readable}. If reading files or resources you 323 * should use the {@link Files#readLines} and {@link Resources#readLines} 324 * methods. 325 * 326 * @param r the object to read from 327 * @return a mutable {@link List} containing all the lines 328 * @throws IOException if an I/O error occurs 329 */ 330 public static List<String> readLines(Readable r) throws IOException { 331 List<String> result = new ArrayList<String>(); 332 LineReader lineReader = new LineReader(r); 333 String line; 334 while ((line = lineReader.readLine()) != null) { 335 result.add(line); 336 } 337 return result; 338 } 339 340 /** 341 * Streams lines from a {@link Readable} and {@link Closeable} object 342 * supplied by a factory, stopping when our callback returns false, or we 343 * have read all of the lines. 344 * 345 * @param supplier the factory to read from 346 * @param callback the LineProcessor to use to handle the lines 347 * @return the output of processing the lines 348 * @throws IOException if an I/O error occurs 349 */ 350 public static <R extends Readable & Closeable, T> T readLines( 351 InputSupplier<R> supplier, LineProcessor<T> callback) throws IOException { 352 boolean threw = true; 353 R r = supplier.getInput(); 354 try { 355 LineReader lineReader = new LineReader(r); 356 String line; 357 while ((line = lineReader.readLine()) != null) { 358 if (!callback.processLine(line)) { 359 break; 360 } 361 } 362 threw = false; 363 } finally { 364 Closeables.close(r, threw); 365 } 366 return callback.getResult(); 367 } 368 369 /** 370 * Joins multiple {@link Reader} suppliers into a single supplier. 371 * Reader returned from the supplier will contain the concatenated data 372 * from the readers of the underlying suppliers. 373 * 374 * <p>Reading from the joined reader will throw a {@link NullPointerException} 375 * if any of the suppliers are null or return null. 376 * 377 * <p>Only one underlying reader will be open at a time. Closing the 378 * joined reader will close the open underlying reader. 379 * 380 * @param suppliers the suppliers to concatenate 381 * @return a supplier that will return a reader containing the concatenated 382 * data 383 */ 384 public static InputSupplier<Reader> join( 385 final Iterable<? extends InputSupplier<? extends Reader>> suppliers) { 386 return new InputSupplier<Reader>() { 387 @Override public Reader getInput() throws IOException { 388 return new MultiReader(suppliers.iterator()); 389 } 390 }; 391 } 392 393 /** Varargs form of {@link #join(Iterable)}. */ 394 public static InputSupplier<Reader> join( 395 InputSupplier<? extends Reader>... suppliers) { 396 return join(Arrays.asList(suppliers)); 397 } 398 399 /** 400 * Discards {@code n} characters of data from the reader. This method 401 * will block until the full amount has been skipped. Does not close the 402 * reader. 403 * 404 * @param reader the reader to read from 405 * @param n the number of characters to skip 406 * @throws EOFException if this stream reaches the end before skipping all 407 * the bytes 408 * @throws IOException if an I/O error occurs 409 */ 410 public static void skipFully(Reader reader, long n) throws IOException { 411 while (n > 0) { 412 long amt = reader.skip(n); 413 if (amt == 0) { 414 // force a blocking read 415 if (reader.read() == -1) { 416 throw new EOFException(); 417 } 418 n--; 419 } else { 420 n -= amt; 421 } 422 } 423 } 424 425 /** 426 * Returns a Writer that sends all output to the given {@link Appendable} 427 * target. Closing the writer will close the target if it is {@link 428 * Closeable}, and flushing the writer will flush the target if it is {@link 429 * java.io.Flushable}. 430 * 431 * @param target the object to which output will be sent 432 * @return a new Writer object, unless target is a Writer, in which case the 433 * target is returned 434 */ 435 public static Writer asWriter(Appendable target) { 436 if (target instanceof Writer) { 437 return (Writer) target; 438 } 439 return new AppendableWriter(target); 440 } 441 }