001/* 002 * Copyright (C) 2012 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; 020 021import com.google.common.collect.ImmutableList; 022import com.google.common.collect.Lists; 023 024import java.io.BufferedReader; 025import java.io.IOException; 026import java.io.Reader; 027import java.io.Writer; 028import java.nio.charset.Charset; 029import java.util.List; 030 031import javax.annotation.Nullable; 032 033/** 034 * A readable source of characters, such as a text file. Unlike a {@link Reader}, a 035 * {@code CharSource} is not an open, stateful stream of characters that can be read and closed. 036 * Instead, it is an immutable <i>supplier</i> of {@code InputStream} instances. 037 * 038 * <p>{@code CharSource} provides two kinds of methods: 039 * <ul> 040 * <li><b>Methods that return a reader:</b> These methods should return a <i>new</i>, independent 041 * instance each time they are called. The caller is responsible for ensuring that the returned 042 * reader is closed. 043 * <li><b>Convenience methods:</b> These are implementations of common operations that are 044 * typically implemented by opening a reader using one of the methods in the first category, 045 * doing something and finally closing the reader that was opened. 046 * </ul> 047 * 048 * <p>Several methods in this class, such as {@link #readLines()}, break the contents of the 049 * source into lines. Like {@link BufferedReader}, these methods break lines on any of {@code \n}, 050 * {@code \r} or {@code \r\n}, do not include the line separator in each line and do not consider 051 * there to be an empty line at the end if the contents are terminated with a line separator. 052 * 053 * <p>Any {@link ByteSource} containing text encoded with a specific {@linkplain Charset character 054 * encoding} may be viewed as a {@code CharSource} using {@link ByteSource#asCharSource(Charset)}. 055 * 056 * @since 14.0 057 * @author Colin Decker 058 */ 059public abstract class CharSource { 060 061 /** 062 * Opens a new {@link Reader} for reading from this source. This method should return a new, 063 * independent reader each time it is called. 064 * 065 * <p>The caller is responsible for ensuring that the returned reader is closed. 066 * 067 * @throws IOException if an I/O error occurs in the process of opening the reader 068 */ 069 public abstract Reader openStream() throws IOException; 070 071 /** 072 * Opens a new {@link BufferedReader} for reading from this source. This method should return a 073 * new, independent reader each time it is called. 074 * 075 * <p>The caller is responsible for ensuring that the returned reader is closed. 076 * 077 * @throws IOException if an I/O error occurs in the process of opening the reader 078 */ 079 public BufferedReader openBufferedStream() throws IOException { 080 Reader reader = openStream(); 081 return (reader instanceof BufferedReader) 082 ? (BufferedReader) reader 083 : new BufferedReader(reader); 084 } 085 086 /** 087 * Appends the contents of this source to the given {@link Appendable} (such as a {@link Writer}). 088 * Does not close {@code appendable} if it is {@code Closeable}. 089 * 090 * @throws IOException if an I/O error occurs in the process of reading from this source or 091 * writing to {@code appendable} 092 */ 093 public long copyTo(Appendable appendable) throws IOException { 094 checkNotNull(appendable); 095 096 Closer closer = Closer.create(); 097 try { 098 Reader reader = closer.register(openStream()); 099 return CharStreams.copy(reader, appendable); 100 } catch (Throwable e) { 101 throw closer.rethrow(e); 102 } finally { 103 closer.close(); 104 } 105 } 106 107 /** 108 * Copies the contents of this source to the given sink. 109 * 110 * @throws IOException if an I/O error occurs in the process of reading from this source or 111 * writing to {@code sink} 112 */ 113 public long copyTo(CharSink sink) throws IOException { 114 checkNotNull(sink); 115 116 Closer closer = Closer.create(); 117 try { 118 Reader reader = closer.register(openStream()); 119 Writer writer = closer.register(sink.openStream()); 120 return CharStreams.copy(reader, writer); 121 } catch (Throwable e) { 122 throw closer.rethrow(e); 123 } finally { 124 closer.close(); 125 } 126 } 127 128 /** 129 * Reads the contents of this source as a string. 130 * 131 * @throws IOException if an I/O error occurs in the process of reading from this source 132 */ 133 public String read() throws IOException { 134 Closer closer = Closer.create(); 135 try { 136 Reader reader = closer.register(openStream()); 137 return CharStreams.toString(reader); 138 } catch (Throwable e) { 139 throw closer.rethrow(e); 140 } finally { 141 closer.close(); 142 } 143 } 144 145 /** 146 * Reads the first link of this source as a string. Returns {@code null} if this source is empty. 147 * 148 * <p>Like {@link BufferedReader}, this method breaks lines on any of {@code \n}, {@code \r} or 149 * {@code \r\n}, does not include the line separator in the returned line and does not consider 150 * there to be an extra empty line at the end if the content is terminated with a line separator. 151 * 152 * @throws IOException if an I/O error occurs in the process of reading from this source 153 */ 154 public @Nullable String readFirstLine() throws IOException { 155 Closer closer = Closer.create(); 156 try { 157 BufferedReader reader = closer.register(openBufferedStream()); 158 return reader.readLine(); 159 } catch (Throwable e) { 160 throw closer.rethrow(e); 161 } finally { 162 closer.close(); 163 } 164 } 165 166 /** 167 * Reads all the lines of this source as a list of strings. The returned list will be empty if 168 * this source is empty. 169 * 170 * <p>Like {@link BufferedReader}, this method breaks lines on any of {@code \n}, {@code \r} or 171 * {@code \r\n}, does not include the line separator in the returned lines and does not consider 172 * there to be an extra empty line at the end if the content is terminated with a line separator. 173 * 174 * @throws IOException if an I/O error occurs in the process of reading from this source 175 */ 176 public ImmutableList<String> readLines() throws IOException { 177 Closer closer = Closer.create(); 178 try { 179 BufferedReader reader = closer.register(openBufferedStream()); 180 List<String> result = Lists.newArrayList(); 181 String line; 182 while ((line = reader.readLine()) != null) { 183 result.add(line); 184 } 185 return ImmutableList.copyOf(result); 186 } catch (Throwable e) { 187 throw closer.rethrow(e); 188 } finally { 189 closer.close(); 190 } 191 } 192}