1 /* 2 * Copyright (C) 2007 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.common.io; 18 19 import static com.google.common.base.Preconditions.checkNotNull; 20 import static com.google.common.base.Preconditions.checkPositionIndexes; 21 22 import com.google.common.annotations.Beta; 23 24 import java.io.Closeable; 25 import java.io.EOFException; 26 import java.io.IOException; 27 import java.io.Reader; 28 import java.io.Writer; 29 import java.nio.CharBuffer; 30 import java.util.ArrayList; 31 import java.util.List; 32 33 /** 34 * Provides utility methods for working with character streams. 35 * 36 * <p>All method parameters must be non-null unless documented otherwise. 37 * 38 * <p>Some of the methods in this class take arguments with a generic type of 39 * {@code Readable & Closeable}. A {@link java.io.Reader} implements both of 40 * those interfaces. Similarly for {@code Appendable & Closeable} and 41 * {@link java.io.Writer}. 42 * 43 * @author Chris Nokleberg 44 * @author Bin Zhu 45 * @author Colin Decker 46 * @since 1.0 47 */ 48 @Beta 49 public final class CharStreams { 50 private static final int BUF_SIZE = 0x800; // 2K chars (4K bytes) 51 CharStreams()52 private CharStreams() {} 53 54 /** 55 * Copies all characters between the {@link Readable} and {@link Appendable} 56 * objects. Does not close or flush either object. 57 * 58 * @param from the object to read from 59 * @param to the object to write to 60 * @return the number of characters copied 61 * @throws IOException if an I/O error occurs 62 */ copy(Readable from, Appendable to)63 public static long copy(Readable from, Appendable to) throws IOException { 64 checkNotNull(from); 65 checkNotNull(to); 66 CharBuffer buf = CharBuffer.allocate(BUF_SIZE); 67 long total = 0; 68 while (from.read(buf) != -1) { 69 buf.flip(); 70 to.append(buf); 71 total += buf.remaining(); 72 buf.clear(); 73 } 74 return total; 75 } 76 77 /** 78 * Reads all characters from a {@link Readable} object into a {@link String}. 79 * Does not close the {@code Readable}. 80 * 81 * @param r the object to read from 82 * @return a string containing all the characters 83 * @throws IOException if an I/O error occurs 84 */ toString(Readable r)85 public static String toString(Readable r) throws IOException { 86 return toStringBuilder(r).toString(); 87 } 88 89 /** 90 * Reads all characters from a {@link Readable} object into a new 91 * {@link StringBuilder} instance. Does not close the {@code Readable}. 92 * 93 * @param r the object to read from 94 * @return a {@link StringBuilder} containing all the characters 95 * @throws IOException if an I/O error occurs 96 */ toStringBuilder(Readable r)97 private static StringBuilder toStringBuilder(Readable r) throws IOException { 98 StringBuilder sb = new StringBuilder(); 99 copy(r, sb); 100 return sb; 101 } 102 103 /** 104 * Reads all of the lines from a {@link Readable} object. The lines do 105 * not include line-termination characters, but do include other 106 * leading and trailing whitespace. 107 * 108 * <p>Does not close the {@code Readable}. If reading files or resources you 109 * should use the {@link Files#readLines} and {@link Resources#readLines} 110 * methods. 111 * 112 * @param r the object to read from 113 * @return a mutable {@link List} containing all the lines 114 * @throws IOException if an I/O error occurs 115 */ readLines(Readable r)116 public static List<String> readLines(Readable r) throws IOException { 117 List<String> result = new ArrayList<String>(); 118 LineReader lineReader = new LineReader(r); 119 String line; 120 while ((line = lineReader.readLine()) != null) { 121 result.add(line); 122 } 123 return result; 124 } 125 126 /** 127 * Streams lines from a {@link Readable} object, stopping when the processor 128 * returns {@code false} or all lines have been read and returning the result 129 * produced by the processor. Does not close {@code readable}. Note that this 130 * method may not fully consume the contents of {@code readable} if the 131 * processor stops processing early. 132 * 133 * @throws IOException if an I/O error occurs 134 * @since 14.0 135 */ readLines( Readable readable, LineProcessor<T> processor)136 public static <T> T readLines( 137 Readable readable, LineProcessor<T> processor) throws IOException { 138 checkNotNull(readable); 139 checkNotNull(processor); 140 141 LineReader lineReader = new LineReader(readable); 142 String line; 143 while ((line = lineReader.readLine()) != null) { 144 if (!processor.processLine(line)) { 145 break; 146 } 147 } 148 return processor.getResult(); 149 } 150 151 /** 152 * Discards {@code n} characters of data from the reader. This method 153 * will block until the full amount has been skipped. Does not close the 154 * reader. 155 * 156 * @param reader the reader to read from 157 * @param n the number of characters to skip 158 * @throws EOFException if this stream reaches the end before skipping all 159 * the characters 160 * @throws IOException if an I/O error occurs 161 */ skipFully(Reader reader, long n)162 public static void skipFully(Reader reader, long n) throws IOException { 163 checkNotNull(reader); 164 while (n > 0) { 165 long amt = reader.skip(n); 166 if (amt == 0) { 167 // force a blocking read 168 if (reader.read() == -1) { 169 throw new EOFException(); 170 } 171 n--; 172 } else { 173 n -= amt; 174 } 175 } 176 } 177 178 /** 179 * Returns a {@link Writer} that simply discards written chars. 180 * 181 * @since 15.0 182 */ nullWriter()183 public static Writer nullWriter() { 184 return NullWriter.INSTANCE; 185 } 186 187 private static final class NullWriter extends Writer { 188 189 private static final NullWriter INSTANCE = new NullWriter(); 190 191 @Override write(int c)192 public void write(int c) { 193 } 194 195 @Override write(char[] cbuf)196 public void write(char[] cbuf) { 197 checkNotNull(cbuf); 198 } 199 200 @Override write(char[] cbuf, int off, int len)201 public void write(char[] cbuf, int off, int len) { 202 checkPositionIndexes(off, off + len, cbuf.length); 203 } 204 205 @Override write(String str)206 public void write(String str) { 207 checkNotNull(str); 208 } 209 210 @Override write(String str, int off, int len)211 public void write(String str, int off, int len) { 212 checkPositionIndexes(off, off + len, str.length()); 213 } 214 215 @Override append(CharSequence csq)216 public Writer append(CharSequence csq) { 217 checkNotNull(csq); 218 return this; 219 } 220 221 @Override append(CharSequence csq, int start, int end)222 public Writer append(CharSequence csq, int start, int end) { 223 checkPositionIndexes(start, end, csq.length()); 224 return this; 225 } 226 227 @Override append(char c)228 public Writer append(char c) { 229 return this; 230 } 231 232 @Override flush()233 public void flush() { 234 } 235 236 @Override close()237 public void close() { 238 } 239 240 @Override toString()241 public String toString() { 242 return "CharStreams.nullWriter()"; 243 } 244 } 245 246 /** 247 * Returns a Writer that sends all output to the given {@link Appendable} 248 * target. Closing the writer will close the target if it is {@link 249 * Closeable}, and flushing the writer will flush the target if it is {@link 250 * java.io.Flushable}. 251 * 252 * @param target the object to which output will be sent 253 * @return a new Writer object, unless target is a Writer, in which case the 254 * target is returned 255 */ asWriter(Appendable target)256 public static Writer asWriter(Appendable target) { 257 if (target instanceof Writer) { 258 return (Writer) target; 259 } 260 return new AppendableWriter(target); 261 } 262 263 // TODO(user): Remove these once Input/OutputSupplier methods are removed 264 asReader(final Readable readable)265 static Reader asReader(final Readable readable) { 266 checkNotNull(readable); 267 if (readable instanceof Reader) { 268 return (Reader) readable; 269 } 270 return new Reader() { 271 @Override 272 public int read(char[] cbuf, int off, int len) throws IOException { 273 return read(CharBuffer.wrap(cbuf, off, len)); 274 } 275 276 @Override 277 public int read(CharBuffer target) throws IOException { 278 return readable.read(target); 279 } 280 281 @Override 282 public void close() throws IOException { 283 if (readable instanceof Closeable) { 284 ((Closeable) readable).close(); 285 } 286 } 287 }; 288 } 289 } 290