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.Reader; 027import java.io.Writer; 028import java.nio.CharBuffer; 029import java.util.ArrayList; 030import java.util.List; 031 032/** 033 * Provides utility methods for working with character streams. 034 * 035 * <p>All method parameters must be non-null unless documented otherwise. 036 * 037 * <p>Some of the methods in this class take arguments with a generic type of {@code Readable & 038 * Closeable}. A {@link java.io.Reader} implements both of those interfaces. Similarly for {@code 039 * Appendable & Closeable} and {@link java.io.Writer}. 040 * 041 * @author Chris Nokleberg 042 * @author Bin Zhu 043 * @author Colin Decker 044 * @since 1.0 045 */ 046@GwtIncompatible 047public final class CharStreams { 048 049 // 2K chars (4K bytes) 050 private static final int DEFAULT_BUF_SIZE = 0x800; 051 052 /** Creates a new {@code CharBuffer} for buffering reads or writes. */ 053 static CharBuffer createBuffer() { 054 return CharBuffer.allocate(DEFAULT_BUF_SIZE); 055 } 056 057 private CharStreams() {} 058 059 /** 060 * Copies all characters between the {@link Readable} and {@link Appendable} objects. Does not 061 * close or flush either object. 062 * 063 * @param from the object to read from 064 * @param to the object to write to 065 * @return the number of characters copied 066 * @throws IOException if an I/O error occurs 067 */ 068 @CanIgnoreReturnValue 069 public static long copy(Readable from, Appendable to) throws IOException { 070 // The most common case is that from is a Reader (like InputStreamReader or StringReader) so 071 // take advantage of that. 072 if (from instanceof Reader) { 073 // optimize for common output types which are optimized to deal with char[] 074 if (to instanceof StringBuilder) { 075 return copyReaderToBuilder((Reader) from, (StringBuilder) to); 076 } else { 077 return copyReaderToWriter((Reader) from, asWriter(to)); 078 } 079 } else { 080 checkNotNull(from); 081 checkNotNull(to); 082 long total = 0; 083 CharBuffer buf = createBuffer(); 084 while (from.read(buf) != -1) { 085 buf.flip(); 086 to.append(buf); 087 total += buf.remaining(); 088 buf.clear(); 089 } 090 return total; 091 } 092 } 093 094 // TODO(lukes): consider allowing callers to pass in a buffer to use, some callers would be able 095 // to reuse buffers, others would be able to size them more appropriately than the constant 096 // defaults 097 098 /** 099 * Copies all characters between the {@link Reader} and {@link StringBuilder} objects. Does not 100 * close or flush the reader. 101 * 102 * <p>This is identical to {@link #copy(Readable, Appendable)} but optimized for these specific 103 * types. CharBuffer has poor performance when being written into or read out of so round tripping 104 * all the bytes through the buffer takes a long time. With these specialized types we can just 105 * use a char array. 106 * 107 * @param from the object to read from 108 * @param to the object to write to 109 * @return the number of characters copied 110 * @throws IOException if an I/O error occurs 111 */ 112 @CanIgnoreReturnValue 113 static long copyReaderToBuilder(Reader from, StringBuilder to) throws IOException { 114 checkNotNull(from); 115 checkNotNull(to); 116 char[] buf = new char[DEFAULT_BUF_SIZE]; 117 int nRead; 118 long total = 0; 119 while ((nRead = from.read(buf)) != -1) { 120 to.append(buf, 0, nRead); 121 total += nRead; 122 } 123 return total; 124 } 125 126 /** 127 * Copies all characters between the {@link Reader} and {@link Writer} objects. Does not close or 128 * flush the reader or writer. 129 * 130 * <p>This is identical to {@link #copy(Readable, Appendable)} but optimized for these specific 131 * types. CharBuffer has poor performance when being written into or read out of so round tripping 132 * all the bytes through the buffer takes a long time. With these specialized types we can just 133 * use a char array. 134 * 135 * @param from the object to read from 136 * @param to the object to write to 137 * @return the number of characters copied 138 * @throws IOException if an I/O error occurs 139 */ 140 @CanIgnoreReturnValue 141 static long copyReaderToWriter(Reader from, Writer to) throws IOException { 142 checkNotNull(from); 143 checkNotNull(to); 144 char[] buf = new char[DEFAULT_BUF_SIZE]; 145 int nRead; 146 long total = 0; 147 while ((nRead = from.read(buf)) != -1) { 148 to.write(buf, 0, nRead); 149 total += nRead; 150 } 151 return total; 152 } 153 154 /** 155 * Reads all characters from a {@link Readable} object into a {@link String}. Does not close the 156 * {@code Readable}. 157 * 158 * @param r the object to read from 159 * @return a string containing all the characters 160 * @throws IOException if an I/O error occurs 161 */ 162 public static String toString(Readable r) throws IOException { 163 return toStringBuilder(r).toString(); 164 } 165 166 /** 167 * Reads all characters from a {@link Readable} object into a new {@link StringBuilder} instance. 168 * Does not close the {@code Readable}. 169 * 170 * @param r the object to read from 171 * @return a {@link StringBuilder} containing all the characters 172 * @throws IOException if an I/O error occurs 173 */ 174 private static StringBuilder toStringBuilder(Readable r) throws IOException { 175 StringBuilder sb = new StringBuilder(); 176 if (r instanceof Reader) { 177 copyReaderToBuilder((Reader) r, sb); 178 } else { 179 copy(r, sb); 180 } 181 return sb; 182 } 183 184 /** 185 * Reads all of the lines from a {@link Readable} object. The lines do not include 186 * line-termination characters, but do include other leading and trailing whitespace. 187 * 188 * <p>Does not close the {@code Readable}. If reading files or resources you should use the {@link 189 * Files#readLines} and {@link Resources#readLines} methods. 190 * 191 * @param r the object to read from 192 * @return a mutable {@link List} containing all the lines 193 * @throws IOException if an I/O error occurs 194 */ 195 @Beta 196 public static List<String> readLines(Readable r) throws IOException { 197 List<String> result = new ArrayList<>(); 198 LineReader lineReader = new LineReader(r); 199 String line; 200 while ((line = lineReader.readLine()) != null) { 201 result.add(line); 202 } 203 return result; 204 } 205 206 /** 207 * Streams lines from a {@link Readable} object, stopping when the processor returns {@code false} 208 * or all lines have been read and returning the result produced by the processor. Does not close 209 * {@code readable}. Note that this method may not fully consume the contents of {@code readable} 210 * if the processor stops processing early. 211 * 212 * @throws IOException if an I/O error occurs 213 * @since 14.0 214 */ 215 @Beta 216 @CanIgnoreReturnValue // some processors won't return a useful result 217 public static <T> T readLines(Readable readable, LineProcessor<T> processor) throws IOException { 218 checkNotNull(readable); 219 checkNotNull(processor); 220 221 LineReader lineReader = new LineReader(readable); 222 String line; 223 while ((line = lineReader.readLine()) != null) { 224 if (!processor.processLine(line)) { 225 break; 226 } 227 } 228 return processor.getResult(); 229 } 230 231 /** 232 * Reads and discards data from the given {@code Readable} until the end of the stream is reached. 233 * Returns the total number of chars read. Does not close the stream. 234 * 235 * @since 20.0 236 */ 237 @Beta 238 @CanIgnoreReturnValue 239 public static long exhaust(Readable readable) throws IOException { 240 long total = 0; 241 long read; 242 CharBuffer buf = createBuffer(); 243 while ((read = readable.read(buf)) != -1) { 244 total += read; 245 buf.clear(); 246 } 247 return total; 248 } 249 250 /** 251 * Discards {@code n} characters of data from the reader. This method will block until the full 252 * amount has been skipped. Does not close the reader. 253 * 254 * @param reader the reader to read from 255 * @param n the number of characters to skip 256 * @throws EOFException if this stream reaches the end before skipping all the characters 257 * @throws IOException if an I/O error occurs 258 */ 259 @Beta 260 public static void skipFully(Reader reader, long n) throws IOException { 261 checkNotNull(reader); 262 while (n > 0) { 263 long amt = reader.skip(n); 264 if (amt == 0) { 265 throw new EOFException(); 266 } 267 n -= amt; 268 } 269 } 270 271 /** 272 * Returns a {@link Writer} that simply discards written chars. 273 * 274 * @since 15.0 275 */ 276 @Beta 277 public static Writer nullWriter() { 278 return NullWriter.INSTANCE; 279 } 280 281 private static final class NullWriter extends Writer { 282 283 private static final NullWriter INSTANCE = new NullWriter(); 284 285 @Override 286 public void write(int c) {} 287 288 @Override 289 public void write(char[] cbuf) { 290 checkNotNull(cbuf); 291 } 292 293 @Override 294 public void write(char[] cbuf, int off, int len) { 295 checkPositionIndexes(off, off + len, cbuf.length); 296 } 297 298 @Override 299 public void write(String str) { 300 checkNotNull(str); 301 } 302 303 @Override 304 public void write(String str, int off, int len) { 305 checkPositionIndexes(off, off + len, str.length()); 306 } 307 308 @Override 309 public Writer append(CharSequence csq) { 310 checkNotNull(csq); 311 return this; 312 } 313 314 @Override 315 public Writer append(CharSequence csq, int start, int end) { 316 checkPositionIndexes(start, end, csq.length()); 317 return this; 318 } 319 320 @Override 321 public Writer append(char c) { 322 return this; 323 } 324 325 @Override 326 public void flush() {} 327 328 @Override 329 public void close() {} 330 331 @Override 332 public String toString() { 333 return "CharStreams.nullWriter()"; 334 } 335 } 336 337 /** 338 * Returns a Writer that sends all output to the given {@link Appendable} target. Closing the 339 * writer will close the target if it is {@link Closeable}, and flushing the writer will flush the 340 * target if it is {@link java.io.Flushable}. 341 * 342 * @param target the object to which output will be sent 343 * @return a new Writer object, unless target is a Writer, in which case the target is returned 344 */ 345 @Beta 346 public static Writer asWriter(Appendable target) { 347 if (target instanceof Writer) { 348 return (Writer) target; 349 } 350 return new AppendableWriter(target); 351 } 352}