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 017package com.google.common.io; 018 019import static com.google.common.base.Preconditions.checkNotNull; 020import static com.google.common.base.Preconditions.checkPositionIndexes; 021 022import com.google.common.annotations.Beta; 023 024import java.io.Closeable; 025import java.io.EOFException; 026import java.io.IOException; 027import java.io.Reader; 028import java.io.Writer; 029import java.nio.CharBuffer; 030import java.util.ArrayList; 031import java.util.List; 032 033/** 034 * Provides utility methods for working with character streams. 035 * 036 * <p>All method parameters must be non-null unless documented otherwise. 037 * 038 * <p>Some of the methods in this class take arguments with a generic type of 039 * {@code Readable & Closeable}. A {@link java.io.Reader} implements both of 040 * those interfaces. Similarly for {@code Appendable & Closeable} and 041 * {@link java.io.Writer}. 042 * 043 * @author Chris Nokleberg 044 * @author Bin Zhu 045 * @author Colin Decker 046 * @since 1.0 047 */ 048@Beta 049public final class CharStreams { 050 private static final int BUF_SIZE = 0x800; // 2K chars (4K bytes) 051 052 private CharStreams() {} 053 054 /** 055 * Copies all characters between the {@link Readable} and {@link Appendable} 056 * objects. Does not close or flush either object. 057 * 058 * @param from the object to read from 059 * @param to the object to write to 060 * @return the number of characters copied 061 * @throws IOException if an I/O error occurs 062 */ 063 public static long copy(Readable from, Appendable to) throws IOException { 064 checkNotNull(from); 065 checkNotNull(to); 066 CharBuffer buf = CharBuffer.allocate(BUF_SIZE); 067 long total = 0; 068 while (from.read(buf) != -1) { 069 buf.flip(); 070 to.append(buf); 071 total += buf.remaining(); 072 buf.clear(); 073 } 074 return total; 075 } 076 077 /** 078 * Reads all characters from a {@link Readable} object into a {@link String}. 079 * Does not close the {@code Readable}. 080 * 081 * @param r the object to read from 082 * @return a string containing all the characters 083 * @throws IOException if an I/O error occurs 084 */ 085 public static String toString(Readable r) throws IOException { 086 return toStringBuilder(r).toString(); 087 } 088 089 /** 090 * Reads all characters from a {@link Readable} object into a new 091 * {@link StringBuilder} instance. Does not close the {@code Readable}. 092 * 093 * @param r the object to read from 094 * @return a {@link StringBuilder} containing all the characters 095 * @throws IOException if an I/O error occurs 096 */ 097 private static StringBuilder toStringBuilder(Readable r) throws IOException { 098 StringBuilder sb = new StringBuilder(); 099 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 */ 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 */ 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 */ 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 */ 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 192 public void write(int c) { 193 } 194 195 @Override 196 public void write(char[] cbuf) { 197 checkNotNull(cbuf); 198 } 199 200 @Override 201 public void write(char[] cbuf, int off, int len) { 202 checkPositionIndexes(off, off + len, cbuf.length); 203 } 204 205 @Override 206 public void write(String str) { 207 checkNotNull(str); 208 } 209 210 @Override 211 public void write(String str, int off, int len) { 212 checkPositionIndexes(off, off + len, str.length()); 213 } 214 215 @Override 216 public Writer append(CharSequence csq) { 217 checkNotNull(csq); 218 return this; 219 } 220 221 @Override 222 public Writer append(CharSequence csq, int start, int end) { 223 checkPositionIndexes(start, end, csq.length()); 224 return this; 225 } 226 227 @Override 228 public Writer append(char c) { 229 return this; 230 } 231 232 @Override 233 public void flush() { 234 } 235 236 @Override 237 public void close() { 238 } 239 240 @Override 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 */ 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 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}