1 /* 2 * Copyright (c) 1996, 2016, 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 /** 30 * Writes text to a character-output stream, buffering characters so as to 31 * provide for the efficient writing of single characters, arrays, and strings. 32 * 33 * <p> The buffer size may be specified, or the default size may be accepted. 34 * The default is large enough for most purposes. 35 * 36 * <p> A newLine() method is provided, which uses the platform's own notion of 37 * line separator as defined by the system property {@code line.separator}. 38 * Not all platforms use the newline character ('\n') to terminate lines. 39 * Calling this method to terminate each output line is therefore preferred to 40 * writing a newline character directly. 41 * 42 * <p> In general, a Writer sends its output immediately to the underlying 43 * character or byte stream. Unless prompt output is required, it is advisable 44 * to wrap a BufferedWriter around any Writer whose write() operations may be 45 * costly, such as FileWriters and OutputStreamWriters. For example, 46 * 47 * <pre> 48 * PrintWriter out 49 * = new PrintWriter(new BufferedWriter(new FileWriter("foo.out"))); 50 * </pre> 51 * 52 * will buffer the PrintWriter's output to the file. Without buffering, each 53 * invocation of a print() method would cause characters to be converted into 54 * bytes that would then be written immediately to the file, which can be very 55 * inefficient. 56 * 57 * @see PrintWriter 58 * @see FileWriter 59 * @see OutputStreamWriter 60 * @see java.nio.file.Files#newBufferedWriter 61 * 62 * @author Mark Reinhold 63 * @since 1.1 64 */ 65 66 public class BufferedWriter extends Writer { 67 68 private Writer out; 69 70 private char cb[]; 71 private int nChars, nextChar; 72 73 private static int defaultCharBufferSize = 8192; 74 75 /** 76 * Creates a buffered character-output stream that uses a default-sized 77 * output buffer. 78 * 79 * @param out A Writer 80 */ BufferedWriter(Writer out)81 public BufferedWriter(Writer out) { 82 this(out, defaultCharBufferSize); 83 } 84 85 /** 86 * Creates a new buffered character-output stream that uses an output 87 * buffer of the given size. 88 * 89 * @param out A Writer 90 * @param sz Output-buffer size, a positive integer 91 * 92 * @exception IllegalArgumentException If {@code sz <= 0} 93 */ BufferedWriter(Writer out, int sz)94 public BufferedWriter(Writer out, int sz) { 95 super(out); 96 if (sz <= 0) 97 throw new IllegalArgumentException("Buffer size <= 0"); 98 this.out = out; 99 cb = new char[sz]; 100 nChars = sz; 101 nextChar = 0; 102 } 103 104 /** Checks to make sure that the stream has not been closed */ ensureOpen()105 private void ensureOpen() throws IOException { 106 if (out == null) 107 throw new IOException("Stream closed"); 108 } 109 110 /** 111 * Flushes the output buffer to the underlying character stream, without 112 * flushing the stream itself. This method is non-private only so that it 113 * may be invoked by PrintStream. 114 */ flushBuffer()115 void flushBuffer() throws IOException { 116 synchronized (lock) { 117 ensureOpen(); 118 if (nextChar == 0) 119 return; 120 out.write(cb, 0, nextChar); 121 nextChar = 0; 122 } 123 } 124 125 /** 126 * Writes a single character. 127 * 128 * @exception IOException If an I/O error occurs 129 */ write(int c)130 public void write(int c) throws IOException { 131 synchronized (lock) { 132 ensureOpen(); 133 if (nextChar >= nChars) 134 flushBuffer(); 135 cb[nextChar++] = (char) c; 136 } 137 } 138 139 /** 140 * Our own little min method, to avoid loading java.lang.Math if we've run 141 * out of file descriptors and we're trying to print a stack trace. 142 */ min(int a, int b)143 private int min(int a, int b) { 144 if (a < b) return a; 145 return b; 146 } 147 148 /** 149 * Writes a portion of an array of characters. 150 * 151 * <p> Ordinarily this method stores characters from the given array into 152 * this stream's buffer, flushing the buffer to the underlying stream as 153 * needed. If the requested length is at least as large as the buffer, 154 * however, then this method will flush the buffer and write the characters 155 * directly to the underlying stream. Thus redundant 156 * {@code BufferedWriter}s will not copy data unnecessarily. 157 * 158 * @param cbuf A character array 159 * @param off Offset from which to start reading characters 160 * @param len Number of characters to write 161 * 162 * @throws IndexOutOfBoundsException 163 * If {@code off} is negative, or {@code len} is negative, 164 * or {@code off + len} is negative or greater than the length 165 * of the given array 166 * 167 * @throws IOException If an I/O error occurs 168 */ write(char cbuf[], int off, int len)169 public void write(char cbuf[], int off, int len) throws IOException { 170 synchronized (lock) { 171 ensureOpen(); 172 if ((off < 0) || (off > cbuf.length) || (len < 0) || 173 ((off + len) > cbuf.length) || ((off + len) < 0)) { 174 throw new IndexOutOfBoundsException(); 175 } else if (len == 0) { 176 return; 177 } 178 179 if (len >= nChars) { 180 /* If the request length exceeds the size of the output buffer, 181 flush the buffer and then write the data directly. In this 182 way buffered streams will cascade harmlessly. */ 183 flushBuffer(); 184 out.write(cbuf, off, len); 185 return; 186 } 187 188 int b = off, t = off + len; 189 while (b < t) { 190 int d = min(nChars - nextChar, t - b); 191 System.arraycopy(cbuf, b, cb, nextChar, d); 192 b += d; 193 nextChar += d; 194 if (nextChar >= nChars) 195 flushBuffer(); 196 } 197 } 198 } 199 200 /** 201 * Writes a portion of a String. 202 * 203 * @implSpec 204 * While the specification of this method in the 205 * {@linkplain java.io.Writer#write(java.lang.String,int,int) superclass} 206 * recommends that an {@link IndexOutOfBoundsException} be thrown 207 * if {@code len} is negative or {@code off + len} is negative, 208 * the implementation in this class does not throw such an exception in 209 * these cases but instead simply writes no characters. 210 * 211 * @param s String to be written 212 * @param off Offset from which to start reading characters 213 * @param len Number of characters to be written 214 * 215 * @throws IndexOutOfBoundsException 216 * If {@code off} is negative, 217 * or {@code off + len} is greater than the length 218 * of the given string 219 * 220 * @throws IOException If an I/O error occurs 221 */ write(String s, int off, int len)222 public void write(String s, int off, int len) throws IOException { 223 synchronized (lock) { 224 ensureOpen(); 225 226 int b = off, t = off + len; 227 while (b < t) { 228 int d = min(nChars - nextChar, t - b); 229 s.getChars(b, b + d, cb, nextChar); 230 b += d; 231 nextChar += d; 232 if (nextChar >= nChars) 233 flushBuffer(); 234 } 235 } 236 } 237 238 /** 239 * Writes a line separator. The line separator string is defined by the 240 * system property {@code line.separator}, and is not necessarily a single 241 * newline ('\n') character. 242 * 243 * @exception IOException If an I/O error occurs 244 */ newLine()245 public void newLine() throws IOException { 246 write(System.lineSeparator()); 247 } 248 249 /** 250 * Flushes the stream. 251 * 252 * @exception IOException If an I/O error occurs 253 */ flush()254 public void flush() throws IOException { 255 synchronized (lock) { 256 flushBuffer(); 257 out.flush(); 258 } 259 } 260 261 @SuppressWarnings("try") close()262 public void close() throws IOException { 263 synchronized (lock) { 264 if (out == null) { 265 return; 266 } 267 try (Writer w = out) { 268 flushBuffer(); 269 } finally { 270 out = null; 271 cb = null; 272 } 273 } 274 } 275 } 276