1 /* 2 * Copyright (C) 2012 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 21 import java.io.BufferedWriter; 22 import java.io.IOException; 23 import java.io.Reader; 24 import java.io.Writer; 25 import java.nio.charset.Charset; 26 27 /** 28 * A destination to which characters can be written, such as a text file. Unlike a {@link Writer}, a 29 * {@code CharSink} is not an open, stateful stream that can be written to and closed. Instead, it 30 * is an immutable <i>supplier</i> of {@code Writer} instances. 31 * 32 * <p>{@code CharSink} provides two kinds of methods: 33 * <ul> 34 * <li><b>Methods that return a writer:</b> These methods should return a <i>new</i>, 35 * independent instance each time they are called. The caller is responsible for ensuring that the 36 * returned writer is closed. 37 * <li><b>Convenience methods:</b> These are implementations of common operations that are 38 * typically implemented by opening a writer using one of the methods in the first category, 39 * doing something and finally closing the writer that was opened. 40 * </ul> 41 * 42 * <p>Any {@link ByteSink} may be viewed as a {@code CharSink} with a specific {@linkplain Charset 43 * character encoding} using {@link ByteSink#asCharSink(Charset)}. Characters written to the 44 * resulting {@code CharSink} will written to the {@code ByteSink} as encoded bytes. 45 * 46 * @since 14.0 47 * @author Colin Decker 48 */ 49 public abstract class CharSink implements OutputSupplier<Writer> { 50 51 /** 52 * Constructor for use by subclasses. 53 */ CharSink()54 protected CharSink() {} 55 56 /** 57 * Opens a new {@link Writer} for writing to this sink. This method should return a new, 58 * independent writer each time it is called. 59 * 60 * <p>The caller is responsible for ensuring that the returned writer is closed. 61 * 62 * @throws IOException if an I/O error occurs in the process of opening the writer 63 */ openStream()64 public abstract Writer openStream() throws IOException; 65 66 /** 67 * This method is a temporary method provided for easing migration from suppliers to sources and 68 * sinks. 69 * 70 * @since 15.0 71 * @deprecated This method is only provided for temporary compatibility with the 72 * {@link OutputSupplier} interface and should not be called directly. Use 73 * {@link #openStream} instead. This method is scheduled for removal in Guava 18.0. 74 */ 75 @Override 76 @Deprecated getOutput()77 public final Writer getOutput() throws IOException { 78 return openStream(); 79 } 80 81 /** 82 * Opens a new buffered {@link Writer} for writing to this sink. The returned stream is not 83 * required to be a {@link BufferedWriter} in order to allow implementations to simply delegate 84 * to {@link #openStream()} when the stream returned by that method does not benefit from 85 * additional buffering. This method should return a new, independent writer each time it is 86 * called. 87 * 88 * <p>The caller is responsible for ensuring that the returned writer is closed. 89 * 90 * @throws IOException if an I/O error occurs in the process of opening the writer 91 * @since 15.0 (in 14.0 with return type {@link BufferedWriter}) 92 */ openBufferedStream()93 public Writer openBufferedStream() throws IOException { 94 Writer writer = openStream(); 95 return (writer instanceof BufferedWriter) 96 ? (BufferedWriter) writer 97 : new BufferedWriter(writer); 98 } 99 100 /** 101 * Writes the given character sequence to this sink. 102 * 103 * @throws IOException if an I/O error in the process of writing to this sink 104 */ write(CharSequence charSequence)105 public void write(CharSequence charSequence) throws IOException { 106 checkNotNull(charSequence); 107 108 Closer closer = Closer.create(); 109 try { 110 Writer out = closer.register(openStream()); 111 out.append(charSequence); 112 out.flush(); // https://code.google.com/p/guava-libraries/issues/detail?id=1330 113 } catch (Throwable e) { 114 throw closer.rethrow(e); 115 } finally { 116 closer.close(); 117 } 118 } 119 120 /** 121 * Writes the given lines of text to this sink with each line (including the last) terminated with 122 * the operating system's default line separator. This method is equivalent to 123 * {@code writeLines(lines, System.getProperty("line.separator"))}. 124 * 125 * @throws IOException if an I/O error occurs in the process of writing to this sink 126 */ writeLines(Iterable<? extends CharSequence> lines)127 public void writeLines(Iterable<? extends CharSequence> lines) throws IOException { 128 writeLines(lines, System.getProperty("line.separator")); 129 } 130 131 /** 132 * Writes the given lines of text to this sink with each line (including the last) terminated with 133 * the given line separator. 134 * 135 * @throws IOException if an I/O error occurs in the process of writing to this sink 136 */ writeLines(Iterable<? extends CharSequence> lines, String lineSeparator)137 public void writeLines(Iterable<? extends CharSequence> lines, String lineSeparator) 138 throws IOException { 139 checkNotNull(lines); 140 checkNotNull(lineSeparator); 141 142 Closer closer = Closer.create(); 143 try { 144 Writer out = closer.register(openBufferedStream()); 145 for (CharSequence line : lines) { 146 out.append(line).append(lineSeparator); 147 } 148 out.flush(); // https://code.google.com/p/guava-libraries/issues/detail?id=1330 149 } catch (Throwable e) { 150 throw closer.rethrow(e); 151 } finally { 152 closer.close(); 153 } 154 } 155 156 /** 157 * Writes all the text from the given {@link Readable} (such as a {@link Reader}) to this sink. 158 * Does not close {@code readable} if it is {@code Closeable}. 159 * 160 * @throws IOException if an I/O error occurs in the process of reading from {@code readable} or 161 * writing to this sink 162 */ writeFrom(Readable readable)163 public long writeFrom(Readable readable) throws IOException { 164 checkNotNull(readable); 165 166 Closer closer = Closer.create(); 167 try { 168 Writer out = closer.register(openStream()); 169 long written = CharStreams.copy(readable, out); 170 out.flush(); // https://code.google.com/p/guava-libraries/issues/detail?id=1330 171 return written; 172 } catch (Throwable e) { 173 throw closer.rethrow(e); 174 } finally { 175 closer.close(); 176 } 177 } 178 } 179