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 boolean threw = true; 151 R in = from.getInput(); 152 try { 153 W out = to.getOutput(); 154 try { 155 long count = copy(in, out); 156 threw = false; 157 return count; 158 } finally { 159 Closeables.close(out, threw); 160 } 161 } finally { 162 Closeables.close(in, threw); 163 } 164 } 165 166 /** 167 * Opens a {@link Readable} object from the supplier, copies all characters 168 * to the {@link Appendable} object, and closes the input. Does not close 169 * or flush the output. 170 * 171 * @param from the input factory 172 * @param to the object to write to 173 * @return the number of characters copied 174 * @throws IOException if an I/O error occurs 175 */ 176 public static <R extends Readable & Closeable> long copy( 177 InputSupplier<R> from, Appendable to) throws IOException { 178 boolean threw = true; 179 R in = from.getInput(); 180 try { 181 long count = copy(in, to); 182 threw = false; 183 return count; 184 } finally { 185 Closeables.close(in, threw); 186 } 187 } 188 189 /** 190 * Copies all characters between the {@link Readable} and {@link Appendable} 191 * objects. Does not close or flush either object. 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 public static long copy(Readable from, Appendable to) throws IOException { 199 CharBuffer buf = CharBuffer.allocate(BUF_SIZE); 200 long total = 0; 201 while (true) { 202 int r = from.read(buf); 203 if (r == -1) { 204 break; 205 } 206 buf.flip(); 207 to.append(buf, 0, r); 208 total += r; 209 } 210 return total; 211 } 212 213 /** 214 * Reads all characters from a {@link Readable} object into a {@link String}. 215 * Does not close the {@code Readable}. 216 * 217 * @param r the object to read from 218 * @return a string containing all the characters 219 * @throws IOException if an I/O error occurs 220 */ 221 public static String toString(Readable r) throws IOException { 222 return toStringBuilder(r).toString(); 223 } 224 225 /** 226 * Returns the characters from a {@link Readable} & {@link Closeable} object 227 * supplied by a factory as a {@link String}. 228 * 229 * @param supplier the factory to read from 230 * @return a string containing all the characters 231 * @throws IOException if an I/O error occurs 232 */ 233 public static <R extends Readable & Closeable> String toString( 234 InputSupplier<R> supplier) throws IOException { 235 return toStringBuilder(supplier).toString(); 236 } 237 238 /** 239 * Reads all characters from a {@link Readable} object into a new 240 * {@link StringBuilder} instance. Does not close the {@code Readable}. 241 * 242 * @param r the object to read from 243 * @return a {@link StringBuilder} containing all the characters 244 * @throws IOException if an I/O error occurs 245 */ 246 private static StringBuilder toStringBuilder(Readable r) throws IOException { 247 StringBuilder sb = new StringBuilder(); 248 copy(r, sb); 249 return sb; 250 } 251 252 /** 253 * Returns the characters from a {@link Readable} & {@link Closeable} object 254 * supplied by a factory as a new {@link StringBuilder} instance. 255 * 256 * @param supplier the factory to read from 257 * @throws IOException if an I/O error occurs 258 */ 259 private static <R extends Readable & Closeable> StringBuilder toStringBuilder( 260 InputSupplier<R> supplier) throws IOException { 261 boolean threw = true; 262 R r = supplier.getInput(); 263 try { 264 StringBuilder result = toStringBuilder(r); 265 threw = false; 266 return result; 267 } finally { 268 Closeables.close(r, threw); 269 } 270 } 271 272 /** 273 * Reads the first line from a {@link Readable} & {@link Closeable} object 274 * supplied by a factory. The line does not include line-termination 275 * characters, but does include other leading and trailing whitespace. 276 * 277 * @param supplier the factory to read from 278 * @return the first line, or null if the reader is empty 279 * @throws IOException if an I/O error occurs 280 */ 281 public static <R extends Readable & Closeable> String readFirstLine( 282 InputSupplier<R> supplier) throws IOException { 283 boolean threw = true; 284 R r = supplier.getInput(); 285 try { 286 String line = new LineReader(r).readLine(); 287 threw = false; 288 return line; 289 } finally { 290 Closeables.close(r, threw); 291 } 292 } 293 294 /** 295 * Reads all of the lines from a {@link Readable} & {@link Closeable} object 296 * supplied by a factory. The lines do not include line-termination 297 * characters, but do include other leading and trailing whitespace. 298 * 299 * @param supplier the factory to read from 300 * @return a mutable {@link List} containing all the lines 301 * @throws IOException if an I/O error occurs 302 */ 303 public static <R extends Readable & Closeable> List<String> readLines( 304 InputSupplier<R> supplier) throws IOException { 305 boolean threw = true; 306 R r = supplier.getInput(); 307 try { 308 List<String> result = readLines(r); 309 threw = false; 310 return result; 311 } finally { 312 Closeables.close(r, threw); 313 } 314 } 315 316 /** 317 * Reads all of the lines from a {@link Readable} object. The lines do 318 * not include line-termination characters, but do include other 319 * leading and trailing whitespace. 320 * 321 * <p>Does not close the {@code Readable}. If reading files or resources you 322 * should use the {@link Files#readLines} and {@link Resources#readLines} 323 * methods. 324 * 325 * @param r the object to read from 326 * @return a mutable {@link List} containing all the lines 327 * @throws IOException if an I/O error occurs 328 */ 329 public static List<String> readLines(Readable r) throws IOException { 330 List<String> result = new ArrayList<String>(); 331 LineReader lineReader = new LineReader(r); 332 String line; 333 while ((line = lineReader.readLine()) != null) { 334 result.add(line); 335 } 336 return result; 337 } 338 339 /** 340 * Streams lines from a {@link Readable} and {@link Closeable} object 341 * supplied by a factory, stopping when our callback returns false, or we 342 * have read all of the lines. 343 * 344 * @param supplier the factory to read from 345 * @param callback the LineProcessor to use to handle the lines 346 * @return the output of processing the lines 347 * @throws IOException if an I/O error occurs 348 */ 349 public static <R extends Readable & Closeable, T> T readLines( 350 InputSupplier<R> supplier, LineProcessor<T> callback) throws IOException { 351 boolean threw = true; 352 R r = supplier.getInput(); 353 try { 354 LineReader lineReader = new LineReader(r); 355 String line; 356 while ((line = lineReader.readLine()) != null) { 357 if (!callback.processLine(line)) { 358 break; 359 } 360 } 361 threw = false; 362 } finally { 363 Closeables.close(r, threw); 364 } 365 return callback.getResult(); 366 } 367 368 /** 369 * Joins multiple {@link Reader} suppliers into a single supplier. 370 * Reader returned from the supplier will contain the concatenated data 371 * from the readers of the underlying suppliers. 372 * 373 * <p>Reading from the joined reader will throw a {@link NullPointerException} 374 * if any of the suppliers are null or return null. 375 * 376 * <p>Only one underlying reader will be open at a time. Closing the 377 * joined reader will close the open underlying reader. 378 * 379 * @param suppliers the suppliers to concatenate 380 * @return a supplier that will return a reader containing the concatenated 381 * data 382 */ 383 public static InputSupplier<Reader> join( 384 final Iterable<? extends InputSupplier<? extends Reader>> suppliers) { 385 return new InputSupplier<Reader>() { 386 @Override public Reader getInput() throws IOException { 387 return new MultiReader(suppliers.iterator()); 388 } 389 }; 390 } 391 392 /** Varargs form of {@link #join(Iterable)}. */ 393 public static InputSupplier<Reader> join( 394 InputSupplier<? extends Reader>... suppliers) { 395 return join(Arrays.asList(suppliers)); 396 } 397 398 /** 399 * Discards {@code n} characters of data from the reader. This method 400 * will block until the full amount has been skipped. Does not close the 401 * reader. 402 * 403 * @param reader the reader to read from 404 * @param n the number of characters to skip 405 * @throws EOFException if this stream reaches the end before skipping all 406 * the bytes 407 * @throws IOException if an I/O error occurs 408 */ 409 public static void skipFully(Reader reader, long n) throws IOException { 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 Writer that sends all output to the given {@link Appendable} 426 * target. Closing the writer will close the target if it is {@link 427 * Closeable}, and flushing the writer will flush the target if it is {@link 428 * java.io.Flushable}. 429 * 430 * @param target the object to which output will be sent 431 * @return a new Writer object, unless target is a Writer, in which case the 432 * target is returned 433 */ 434 public static Writer asWriter(Appendable target) { 435 if (target instanceof Writer) { 436 return (Writer) target; 437 } 438 return new AppendableWriter(target); 439 } 440 }