1 /* 2 * Copyright (c) 1996, 2011, 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 */ nullWriter()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 */ Writer()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 */ Writer(Object lock)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 */ write(int c)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 */ write(char cbuf[])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 */ write(char cbuf[], int off, int len)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 */ write(String str)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 */ write(String str, int off, int len)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 */ append(CharSequence csq)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 */ append(CharSequence csq, int start, int end)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 */ append(char c)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 */ flush()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 */ close()419 public abstract void close() throws IOException; 420 421 } 422