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.Preconditions; 021 022 import java.io.Closeable; 023 import java.io.EOFException; 024 import java.io.IOException; 025 import java.io.InputStream; 026 import java.io.InputStreamReader; 027 import java.io.OutputStream; 028 import java.io.OutputStreamWriter; 029 import java.io.Reader; 030 import java.io.StringReader; 031 import java.io.Writer; 032 import java.nio.CharBuffer; 033 import java.nio.charset.Charset; 034 import java.util.ArrayList; 035 import java.util.Arrays; 036 import java.util.List; 037 038 /** 039 * Provides utility methods for working with character streams. 040 * 041 * <p>All method parameters must be non-null unless documented otherwise. 042 * 043 * <p>Some of the methods in this class take arguments with a generic type of 044 * {@code Readable & Closeable}. A {@link java.io.Reader} implements both of 045 * those interfaces. Similarly for {@code Appendable & Closeable} and 046 * {@link java.io.Writer}. 047 * 048 * @author Chris Nokleberg 049 * @author Bin Zhu 050 * @since 1.0 051 */ 052 @Beta 053 public final class CharStreams { 054 private static final int BUF_SIZE = 0x800; // 2K chars (4K bytes) 055 056 private CharStreams() {} 057 058 /** 059 * Returns a factory that will supply instances of {@link StringReader} that 060 * read a string value. 061 * 062 * @param value the string to read 063 * @return the factory 064 */ 065 public static InputSupplier<StringReader> newReaderSupplier( 066 final String value) { 067 Preconditions.checkNotNull(value); 068 return new InputSupplier<StringReader>() { 069 @Override 070 public StringReader getInput() { 071 return new StringReader(value); 072 } 073 }; 074 } 075 076 /** 077 * Returns a factory that will supply instances of {@link InputStreamReader}, 078 * using the given {@link InputStream} factory and character set. 079 * 080 * @param in the factory that will be used to open input streams 081 * @param charset the character set used to decode the input stream 082 * @return the factory 083 */ 084 public static InputSupplier<InputStreamReader> newReaderSupplier( 085 final InputSupplier<? extends InputStream> in, final Charset charset) { 086 Preconditions.checkNotNull(in); 087 Preconditions.checkNotNull(charset); 088 return new InputSupplier<InputStreamReader>() { 089 @Override 090 public InputStreamReader getInput() throws IOException { 091 return new InputStreamReader(in.getInput(), charset); 092 } 093 }; 094 } 095 096 /** 097 * Returns a factory that will supply instances of {@link OutputStreamWriter}, 098 * using the given {@link OutputStream} factory and character set. 099 * 100 * @param out the factory that will be used to open output streams 101 * @param charset the character set used to encode the output stream 102 * @return the factory 103 */ 104 public static OutputSupplier<OutputStreamWriter> newWriterSupplier( 105 final OutputSupplier<? extends OutputStream> out, final Charset charset) { 106 Preconditions.checkNotNull(out); 107 Preconditions.checkNotNull(charset); 108 return new OutputSupplier<OutputStreamWriter>() { 109 @Override 110 public OutputStreamWriter getOutput() throws IOException { 111 return new OutputStreamWriter(out.getOutput(), charset); 112 } 113 }; 114 } 115 116 /** 117 * Writes a character sequence (such as a string) to an appendable 118 * object from the given supplier. 119 * 120 * @param from the character sequence to write 121 * @param to the output supplier 122 * @throws IOException if an I/O error occurs 123 */ 124 public static <W extends Appendable & Closeable> void write(CharSequence from, 125 OutputSupplier<W> to) throws IOException { 126 Preconditions.checkNotNull(from); 127 boolean threw = true; 128 W out = to.getOutput(); 129 try { 130 out.append(from); 131 threw = false; 132 } finally { 133 Closeables.close(out, threw); 134 } 135 } 136 137 /** 138 * Opens {@link Readable} and {@link Appendable} objects from the 139 * given factories, copies all characters between the two, and closes 140 * them. 141 * 142 * @param from the input factory 143 * @param to the output factory 144 * @return the number of characters copied 145 * @throws IOException if an I/O error occurs 146 */ 147 public static <R extends Readable & Closeable, 148 W extends Appendable & Closeable> long copy(InputSupplier<R> from, 149 OutputSupplier<W> to) throws IOException { 150 int successfulOps = 0; 151 R in = from.getInput(); 152 try { 153 W out = to.getOutput(); 154 try { 155 long count = copy(in, out); 156 successfulOps++; 157 return count; 158 } finally { 159 Closeables.close(out, successfulOps < 1); 160 successfulOps++; 161 } 162 } finally { 163 Closeables.close(in, successfulOps < 2); 164 } 165 } 166 167 /** 168 * Opens a {@link Readable} object from the supplier, copies all characters 169 * to the {@link Appendable} object, and closes the input. Does not close 170 * or flush the output. 171 * 172 * @param from the input factory 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 <R extends Readable & Closeable> long copy( 178 InputSupplier<R> from, Appendable to) throws IOException { 179 boolean threw = true; 180 R in = from.getInput(); 181 try { 182 long count = copy(in, to); 183 threw = false; 184 return count; 185 } finally { 186 Closeables.close(in, threw); 187 } 188 } 189 190 /** 191 * Copies all characters between the {@link Readable} and {@link Appendable} 192 * objects. Does not close or flush either object. 193 * 194 * @param from the object to read from 195 * @param to the object to write to 196 * @return the number of characters copied 197 * @throws IOException if an I/O error occurs 198 */ 199 public static long copy(Readable from, Appendable to) throws IOException { 200 CharBuffer buf = CharBuffer.allocate(BUF_SIZE); 201 long total = 0; 202 while (true) { 203 int r = from.read(buf); 204 if (r == -1) { 205 break; 206 } 207 buf.flip(); 208 to.append(buf, 0, r); 209 total += r; 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 }