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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
254 public void flush() throws IOException {
255 synchronized (lock) {
256 flushBuffer();
257 out.flush();
258 }
259 }
260
261 @SuppressWarnings("try")
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