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 throw new EOFException(); 168 } 169 n -= amt; 170 } 171 } 172 173 /** 174 * Returns a {@link Writer} that simply discards written chars. 175 * 176 * @since 15.0 177 */ 178 public static Writer nullWriter() { 179 return NullWriter.INSTANCE; 180 } 181 182 private static final class NullWriter extends Writer { 183 184 private static final NullWriter INSTANCE = new NullWriter(); 185 186 @Override 187 public void write(int c) { 188 } 189 190 @Override 191 public void write(char[] cbuf) { 192 checkNotNull(cbuf); 193 } 194 195 @Override 196 public void write(char[] cbuf, int off, int len) { 197 checkPositionIndexes(off, off + len, cbuf.length); 198 } 199 200 @Override 201 public void write(String str) { 202 checkNotNull(str); 203 } 204 205 @Override 206 public void write(String str, int off, int len) { 207 checkPositionIndexes(off, off + len, str.length()); 208 } 209 210 @Override 211 public Writer append(CharSequence csq) { 212 checkNotNull(csq); 213 return this; 214 } 215 216 @Override 217 public Writer append(CharSequence csq, int start, int end) { 218 checkPositionIndexes(start, end, csq.length()); 219 return this; 220 } 221 222 @Override 223 public Writer append(char c) { 224 return this; 225 } 226 227 @Override 228 public void flush() { 229 } 230 231 @Override 232 public void close() { 233 } 234 235 @Override 236 public String toString() { 237 return "CharStreams.nullWriter()"; 238 } 239 } 240 241 /** 242 * Returns a Writer that sends all output to the given {@link Appendable} 243 * target. Closing the writer will close the target if it is {@link 244 * Closeable}, and flushing the writer will flush the target if it is {@link 245 * java.io.Flushable}. 246 * 247 * @param target the object to which output will be sent 248 * @return a new Writer object, unless target is a Writer, in which case the 249 * target is returned 250 */ 251 public static Writer asWriter(Appendable target) { 252 if (target instanceof Writer) { 253 return (Writer) target; 254 } 255 return new AppendableWriter(target); 256 } 257 258 // TODO(cgdecker): Remove these once Input/OutputSupplier methods are removed 259 260 static Reader asReader(final Readable readable) { 261 checkNotNull(readable); 262 if (readable instanceof Reader) { 263 return (Reader) readable; 264 } 265 return new Reader() { 266 @Override 267 public int read(char[] cbuf, int off, int len) throws IOException { 268 return read(CharBuffer.wrap(cbuf, off, len)); 269 } 270 271 @Override 272 public int read(CharBuffer target) throws IOException { 273 return readable.read(target); 274 } 275 276 @Override 277 public void close() throws IOException { 278 if (readable instanceof Closeable) { 279 ((Closeable) readable).close(); 280 } 281 } 282 }; 283 } 284}