• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License
10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11  * or implied. See the License for the specific language governing permissions and limitations under
12  * the License.
13  */
14 
15 package com.google.common.io;
16 
17 import static com.google.common.base.Preconditions.checkNotNull;
18 
19 import com.google.common.annotations.GwtIncompatible;
20 import com.google.errorprone.annotations.CanIgnoreReturnValue;
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  *
34  * <ul>
35  *   <li><b>Methods that return a writer:</b> These methods should return a <i>new</i>, independent
36  *       instance each time they are called. The caller is responsible for ensuring that the
37  *       returned writer is closed.
38  *   <li><b>Convenience methods:</b> These are implementations of common operations that are
39  *       typically implemented by opening a writer using one of the methods in the first category,
40  *       doing something and finally closing the writer that was opened.
41  * </ul>
42  *
43  * <p>Any {@link ByteSink} may be viewed as a {@code CharSink} with a specific {@linkplain Charset
44  * character encoding} using {@link ByteSink#asCharSink(Charset)}. Characters written to the
45  * resulting {@code CharSink} will written to the {@code ByteSink} as encoded bytes.
46  *
47  * @since 14.0
48  * @author Colin Decker
49  */
50 @GwtIncompatible
51 public abstract class CharSink {
52 
53   /** Constructor for use by subclasses. */
CharSink()54   protected CharSink() {}
55 
56   /**
57    * Opens a new {@link Writer} for writing to this sink. This method returns a new, independent
58    * 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 while opening the writer
63    */
openStream()64   public abstract Writer openStream() throws IOException;
65 
66   /**
67    * Opens a new buffered {@link Writer} for writing to this sink. The returned stream is not
68    * required to be a {@link BufferedWriter} in order to allow implementations to simply delegate to
69    * {@link #openStream()} when the stream returned by that method does not benefit from additional
70    * buffering. This method returns a new, independent writer each time it is called.
71    *
72    * <p>The caller is responsible for ensuring that the returned writer is closed.
73    *
74    * @throws IOException if an I/O error occurs while opening the writer
75    * @since 15.0 (in 14.0 with return type {@link BufferedWriter})
76    */
openBufferedStream()77   public Writer openBufferedStream() throws IOException {
78     Writer writer = openStream();
79     return (writer instanceof BufferedWriter)
80         ? (BufferedWriter) writer
81         : new BufferedWriter(writer);
82   }
83 
84   /**
85    * Writes the given character sequence to this sink.
86    *
87    * @throws IOException if an I/O error while writing to this sink
88    */
write(CharSequence charSequence)89   public void write(CharSequence charSequence) throws IOException {
90     checkNotNull(charSequence);
91 
92     Closer closer = Closer.create();
93     try {
94       Writer out = closer.register(openStream());
95       out.append(charSequence);
96       out.flush(); // https://code.google.com/p/guava-libraries/issues/detail?id=1330
97     } catch (Throwable e) {
98       throw closer.rethrow(e);
99     } finally {
100       closer.close();
101     }
102   }
103 
104   /**
105    * Writes the given lines of text to this sink with each line (including the last) terminated with
106    * the operating system's default line separator. This method is equivalent to {@code
107    * writeLines(lines, System.getProperty("line.separator"))}.
108    *
109    * @throws IOException if an I/O error occurs while writing to this sink
110    */
writeLines(Iterable<? extends CharSequence> lines)111   public void writeLines(Iterable<? extends CharSequence> lines) throws IOException {
112     writeLines(lines, System.getProperty("line.separator"));
113   }
114 
115   /**
116    * Writes the given lines of text to this sink with each line (including the last) terminated with
117    * the given line separator.
118    *
119    * @throws IOException if an I/O error occurs while writing to this sink
120    */
writeLines(Iterable<? extends CharSequence> lines, String lineSeparator)121   public void writeLines(Iterable<? extends CharSequence> lines, String lineSeparator)
122       throws IOException {
123     checkNotNull(lines);
124     checkNotNull(lineSeparator);
125 
126     Closer closer = Closer.create();
127     try {
128       Writer out = closer.register(openBufferedStream());
129       for (CharSequence line : lines) {
130         out.append(line).append(lineSeparator);
131       }
132       out.flush(); // https://code.google.com/p/guava-libraries/issues/detail?id=1330
133     } catch (Throwable e) {
134       throw closer.rethrow(e);
135     } finally {
136       closer.close();
137     }
138   }
139 
140   /**
141    * Writes all the text from the given {@link Readable} (such as a {@link Reader}) to this sink.
142    * Does not close {@code readable} if it is {@code Closeable}.
143    *
144    * @return the number of characters written
145    * @throws IOException if an I/O error occurs while reading from {@code readable} or writing to
146    *     this sink
147    */
148   @CanIgnoreReturnValue
writeFrom(Readable readable)149   public long writeFrom(Readable readable) throws IOException {
150     checkNotNull(readable);
151 
152     Closer closer = Closer.create();
153     try {
154       Writer out = closer.register(openStream());
155       long written = CharStreams.copy(readable, out);
156       out.flush(); // https://code.google.com/p/guava-libraries/issues/detail?id=1330
157       return written;
158     } catch (Throwable e) {
159       throw closer.rethrow(e);
160     } finally {
161       closer.close();
162     }
163   }
164 }
165