1 /*
2 * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.io;
27
28
29 import java.util.Objects;
30
31 /**
32 * Abstract class for writing to character streams. The only methods that a
33 * subclass must implement are write(char[], int, int), flush(), and close().
34 * Most subclasses, however, will override some of the methods defined here in
35 * order to provide higher efficiency, additional functionality, or both.
36 *
37 * @see BufferedWriter
38 * @see CharArrayWriter
39 * @see FilterWriter
40 * @see OutputStreamWriter
41 * @see FileWriter
42 * @see PipedWriter
43 * @see PrintWriter
44 * @see StringWriter
45 * @see Reader
46 *
47 * @author Mark Reinhold
48 * @since 1.1
49 */
50
51 public abstract class Writer implements Appendable, Closeable, Flushable {
52
53 /**
54 * Temporary buffer used to hold writes of strings and single characters
55 */
56 private char[] writeBuffer;
57
58 /**
59 * Size of writeBuffer, must be >= 1
60 */
61 private static final int WRITE_BUFFER_SIZE = 1024;
62
63 /**
64 * Returns a new {@code Writer} which discards all characters. The
65 * returned stream is initially open. The stream is closed by calling
66 * the {@code close()} method. Subsequent calls to {@code close()} have
67 * no effect.
68 *
69 * <p> While the stream is open, the {@code append(char)}, {@code
70 * append(CharSequence)}, {@code append(CharSequence, int, int)},
71 * {@code flush()}, {@code write(int)}, {@code write(char[])}, and
72 * {@code write(char[], int, int)} methods do nothing. After the stream
73 * has been closed, these methods all throw {@code IOException}.
74 *
75 * <p> The {@link #lock object} used to synchronize operations on the
76 * returned {@code Writer} is not specified.
77 *
78 * @return a {@code Writer} which discards all characters
79 *
80 * @since 11
81 */
82 public static Writer nullWriter() {
83 return new Writer() {
84 private volatile boolean closed;
85
86 private void ensureOpen() throws IOException {
87 if (closed) {
88 throw new IOException("Stream closed");
89 }
90 }
91
92 @Override
93 public Writer append(char c) throws IOException {
94 ensureOpen();
95 return this;
96 }
97
98 @Override
99 public Writer append(CharSequence csq) throws IOException {
100 ensureOpen();
101 return this;
102 }
103
104 @Override
105 public Writer append(CharSequence csq, int start, int end) throws IOException {
106 ensureOpen();
107 if (csq != null) {
108 Objects.checkFromToIndex(start, end, csq.length());
109 }
110 return this;
111 }
112
113 @Override
114 public void write(int c) throws IOException {
115 ensureOpen();
116 }
117
118 @Override
119 public void write(char[] cbuf, int off, int len) throws IOException {
120 Objects.checkFromIndexSize(off, len, cbuf.length);
121 ensureOpen();
122 }
123
124 @Override
125 public void write(String str) throws IOException {
126 Objects.requireNonNull(str);
127 ensureOpen();
128 }
129
130 @Override
131 public void write(String str, int off, int len) throws IOException {
132 Objects.checkFromIndexSize(off, len, str.length());
133 ensureOpen();
134 }
135
136 @Override
137 public void flush() throws IOException {
138 ensureOpen();
139 }
140
141 @Override
142 public void close() throws IOException {
143 closed = true;
144 }
145 };
146 }
147
148 /**
149 * The object used to synchronize operations on this stream. For
150 * efficiency, a character-stream object may use an object other than
151 * itself to protect critical sections. A subclass should therefore use
152 * the object in this field rather than {@code this} or a synchronized
153 * method.
154 */
155 protected Object lock;
156
157 /**
158 * Creates a new character-stream writer whose critical sections will
159 * synchronize on the writer itself.
160 */
161 protected Writer() {
162 this.lock = this;
163 }
164
165 /**
166 * Creates a new character-stream writer whose critical sections will
167 * synchronize on the given object.
168 *
169 * @param lock
170 * Object to synchronize on
171 */
172 protected Writer(Object lock) {
173 if (lock == null) {
174 throw new NullPointerException();
175 }
176 this.lock = lock;
177 }
178
179 /**
180 * Writes a single character. The character to be written is contained in
181 * the 16 low-order bits of the given integer value; the 16 high-order bits
182 * are ignored.
183 *
184 * <p> Subclasses that intend to support efficient single-character output
185 * should override this method.
186 *
187 * @param c
188 * int specifying a character to be written
189 *
190 * @throws IOException
191 * If an I/O error occurs
192 */
193 public void write(int c) throws IOException {
194 synchronized (lock) {
195 if (writeBuffer == null){
196 writeBuffer = new char[WRITE_BUFFER_SIZE];
197 }
198 writeBuffer[0] = (char) c;
199 write(writeBuffer, 0, 1);
200 }
201 }
202
203 /**
204 * Writes an array of characters.
205 *
206 * @param cbuf
207 * Array of characters to be written
208 *
209 * @throws IOException
210 * If an I/O error occurs
211 */
212 public void write(char cbuf[]) throws IOException {
213 write(cbuf, 0, cbuf.length);
214 }
215
216 /**
217 * Writes a portion of an array of characters.
218 *
219 * @param cbuf
220 * Array of characters
221 *
222 * @param off
223 * Offset from which to start writing characters
224 *
225 * @param len
226 * Number of characters to write
227 *
228 * @throws IndexOutOfBoundsException
229 * Implementations should throw this exception
230 * if {@code off} is negative, or {@code len} is negative,
231 * or {@code off + len} is negative or greater than the length
232 * of the given array
233 *
234 * @throws IOException
235 * If an I/O error occurs
236 */
237 public abstract void write(char cbuf[], int off, int len) throws IOException;
238
239 /**
240 * Writes a string.
241 *
242 * @param str
243 * String to be written
244 *
245 * @throws IOException
246 * If an I/O error occurs
247 */
248 public void write(String str) throws IOException {
249 write(str, 0, str.length());
250 }
251
252 /**
253 * Writes a portion of a string.
254 *
255 * @implSpec
256 * The implementation in this class throws an
257 * {@code IndexOutOfBoundsException} for the indicated conditions;
258 * overriding methods may choose to do otherwise.
259 *
260 * @param str
261 * A String
262 *
263 * @param off
264 * Offset from which to start writing characters
265 *
266 * @param len
267 * Number of characters to write
268 *
269 * @throws IndexOutOfBoundsException
270 * Implementations should throw this exception
271 * if {@code off} is negative, or {@code len} is negative,
272 * or {@code off + len} is negative or greater than the length
273 * of the given string
274 *
275 * @throws IOException
276 * If an I/O error occurs
277 */
278 public void write(String str, int off, int len) throws IOException {
279 synchronized (lock) {
280 char cbuf[];
281 if (len <= WRITE_BUFFER_SIZE) {
282 if (writeBuffer == null) {
283 writeBuffer = new char[WRITE_BUFFER_SIZE];
284 }
285 cbuf = writeBuffer;
286 } else { // Don't permanently allocate very large buffers.
287 cbuf = new char[len];
288 }
289 str.getChars(off, (off + len), cbuf, 0);
290 write(cbuf, 0, len);
291 }
292 }
293
294 /**
295 * Appends the specified character sequence to this writer.
296 *
297 * <p> An invocation of this method of the form {@code out.append(csq)}
298 * behaves in exactly the same way as the invocation
299 *
300 * <pre>
301 * out.write(csq.toString()) </pre>
302 *
303 * <p> Depending on the specification of {@code toString} for the
304 * character sequence {@code csq}, the entire sequence may not be
305 * appended. For instance, invoking the {@code toString} method of a
306 * character buffer will return a subsequence whose content depends upon
307 * the buffer's position and limit.
308 *
309 * @param csq
310 * The character sequence to append. If {@code csq} is
311 * {@code null}, then the four characters {@code "null"} are
312 * appended to this writer.
313 *
314 * @return This writer
315 *
316 * @throws IOException
317 * If an I/O error occurs
318 *
319 * @since 1.5
320 */
321 public Writer append(CharSequence csq) throws IOException {
322 write(String.valueOf(csq));
323 return this;
324 }
325
326 /**
327 * Appends a subsequence of the specified character sequence to this writer.
328 * {@code Appendable}.
329 *
330 * <p> An invocation of this method of the form
331 * {@code out.append(csq, start, end)} when {@code csq}
332 * is not {@code null} behaves in exactly the
333 * same way as the invocation
334 *
335 * <pre>{@code
336 * out.write(csq.subSequence(start, end).toString())
337 * }</pre>
338 *
339 * @param csq
340 * The character sequence from which a subsequence will be
341 * appended. If {@code csq} is {@code null}, then characters
342 * will be appended as if {@code csq} contained the four
343 * characters {@code "null"}.
344 *
345 * @param start
346 * The index of the first character in the subsequence
347 *
348 * @param end
349 * The index of the character following the last character in the
350 * subsequence
351 *
352 * @return This writer
353 *
354 * @throws IndexOutOfBoundsException
355 * If {@code start} or {@code end} are negative, {@code start}
356 * is greater than {@code end}, or {@code end} is greater than
357 * {@code csq.length()}
358 *
359 * @throws IOException
360 * If an I/O error occurs
361 *
362 * @since 1.5
363 */
364 public Writer append(CharSequence csq, int start, int end) throws IOException {
365 if (csq == null) csq = "null";
366 return append(csq.subSequence(start, end));
367 }
368
369 /**
370 * Appends the specified character to this writer.
371 *
372 * <p> An invocation of this method of the form {@code out.append(c)}
373 * behaves in exactly the same way as the invocation
374 *
375 * <pre>
376 * out.write(c) </pre>
377 *
378 * @param c
379 * The 16-bit character to append
380 *
381 * @return This writer
382 *
383 * @throws IOException
384 * If an I/O error occurs
385 *
386 * @since 1.5
387 */
388 public Writer append(char c) throws IOException {
389 write(c);
390 return this;
391 }
392
393 /**
394 * Flushes the stream. If the stream has saved any characters from the
395 * various write() methods in a buffer, write them immediately to their
396 * intended destination. Then, if that destination is another character or
397 * byte stream, flush it. Thus one flush() invocation will flush all the
398 * buffers in a chain of Writers and OutputStreams.
399 *
400 * <p> If the intended destination of this stream is an abstraction provided
401 * by the underlying operating system, for example a file, then flushing the
402 * stream guarantees only that bytes previously written to the stream are
403 * passed to the operating system for writing; it does not guarantee that
404 * they are actually written to a physical device such as a disk drive.
405 *
406 * @throws IOException
407 * If an I/O error occurs
408 */
409 public abstract void flush() throws IOException;
410
411 /**
412 * Closes the stream, flushing it first. Once the stream has been closed,
413 * further write() or flush() invocations will cause an IOException to be
414 * thrown. Closing a previously closed stream has no effect.
415 *
416 * @throws IOException
417 * If an I/O error occurs
418 */
419 public abstract void close() throws IOException;
420
421 }
422