001: /*
002: * Copyright 1996-2005 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package java.io;
027:
028: /**
029: * Writes text to a character-output stream, buffering characters so as to
030: * provide for the efficient writing of single characters, arrays, and strings.
031: *
032: * <p> The buffer size may be specified, or the default size may be accepted.
033: * The default is large enough for most purposes.
034: *
035: * <p> A newLine() method is provided, which uses the platform's own notion of
036: * line separator as defined by the system property <tt>line.separator</tt>.
037: * Not all platforms use the newline character ('\n') to terminate lines.
038: * Calling this method to terminate each output line is therefore preferred to
039: * writing a newline character directly.
040: *
041: * <p> In general, a Writer sends its output immediately to the underlying
042: * character or byte stream. Unless prompt output is required, it is advisable
043: * to wrap a BufferedWriter around any Writer whose write() operations may be
044: * costly, such as FileWriters and OutputStreamWriters. For example,
045: *
046: * <pre>
047: * PrintWriter out
048: * = new PrintWriter(new BufferedWriter(new FileWriter("foo.out")));
049: * </pre>
050: *
051: * will buffer the PrintWriter's output to the file. Without buffering, each
052: * invocation of a print() method would cause characters to be converted into
053: * bytes that would then be written immediately to the file, which can be very
054: * inefficient.
055: *
056: * @see PrintWriter
057: * @see FileWriter
058: * @see OutputStreamWriter
059: *
060: * @version 1.35, 07/05/05
061: * @author Mark Reinhold
062: * @since JDK1.1
063: */
064:
065: public class BufferedWriter extends Writer {
066:
067: private Writer out;
068:
069: private char cb[];
070: private int nChars, nextChar;
071:
072: private static int defaultCharBufferSize = 8192;
073:
074: /**
075: * Line separator string. This is the value of the line.separator
076: * property at the moment that the stream was created.
077: */
078: private String lineSeparator;
079:
080: /**
081: * Creates a buffered character-output stream that uses a default-sized
082: * output buffer.
083: *
084: * @param out A Writer
085: */
086: public BufferedWriter(Writer out) {
087: this (out, defaultCharBufferSize);
088: }
089:
090: /**
091: * Creates a new buffered character-output stream that uses an output
092: * buffer of the given size.
093: *
094: * @param out A Writer
095: * @param sz Output-buffer size, a positive integer
096: *
097: * @exception IllegalArgumentException If sz is <= 0
098: */
099: public BufferedWriter(Writer out, int sz) {
100: super (out);
101: if (sz <= 0)
102: throw new IllegalArgumentException("Buffer size <= 0");
103: this .out = out;
104: cb = new char[sz];
105: nChars = sz;
106: nextChar = 0;
107:
108: lineSeparator = (String) java.security.AccessController
109: .doPrivileged(new sun.security.action.GetPropertyAction(
110: "line.separator"));
111: }
112:
113: /** Checks to make sure that the stream has not been closed */
114: private void ensureOpen() throws IOException {
115: if (out == null)
116: throw new IOException("Stream closed");
117: }
118:
119: /**
120: * Flushes the output buffer to the underlying character stream, without
121: * flushing the stream itself. This method is non-private only so that it
122: * may be invoked by PrintStream.
123: */
124: void flushBuffer() throws IOException {
125: synchronized (lock) {
126: ensureOpen();
127: if (nextChar == 0)
128: return;
129: out.write(cb, 0, nextChar);
130: nextChar = 0;
131: }
132: }
133:
134: /**
135: * Writes a single character.
136: *
137: * @exception IOException If an I/O error occurs
138: */
139: public void write(int c) throws IOException {
140: synchronized (lock) {
141: ensureOpen();
142: if (nextChar >= nChars)
143: flushBuffer();
144: cb[nextChar++] = (char) c;
145: }
146: }
147:
148: /**
149: * Our own little min method, to avoid loading java.lang.Math if we've run
150: * out of file descriptors and we're trying to print a stack trace.
151: */
152: private int min(int a, int b) {
153: if (a < b)
154: return a;
155: return b;
156: }
157:
158: /**
159: * Writes a portion of an array of characters.
160: *
161: * <p> Ordinarily this method stores characters from the given array into
162: * this stream's buffer, flushing the buffer to the underlying stream as
163: * needed. If the requested length is at least as large as the buffer,
164: * however, then this method will flush the buffer and write the characters
165: * directly to the underlying stream. Thus redundant
166: * <code>BufferedWriter</code>s will not copy data unnecessarily.
167: *
168: * @param cbuf A character array
169: * @param off Offset from which to start reading characters
170: * @param len Number of characters to write
171: *
172: * @exception IOException If an I/O error occurs
173: */
174: public void write(char cbuf[], int off, int len) throws IOException {
175: synchronized (lock) {
176: ensureOpen();
177: if ((off < 0) || (off > cbuf.length) || (len < 0)
178: || ((off + len) > cbuf.length) || ((off + len) < 0)) {
179: throw new IndexOutOfBoundsException();
180: } else if (len == 0) {
181: return;
182: }
183:
184: if (len >= nChars) {
185: /* If the request length exceeds the size of the output buffer,
186: flush the buffer and then write the data directly. In this
187: way buffered streams will cascade harmlessly. */
188: flushBuffer();
189: out.write(cbuf, off, len);
190: return;
191: }
192:
193: int b = off, t = off + len;
194: while (b < t) {
195: int d = min(nChars - nextChar, t - b);
196: System.arraycopy(cbuf, b, cb, nextChar, d);
197: b += d;
198: nextChar += d;
199: if (nextChar >= nChars)
200: flushBuffer();
201: }
202: }
203: }
204:
205: /**
206: * Writes a portion of a String.
207: *
208: * <p> If the value of the <tt>len</tt> parameter is negative then no
209: * characters are written. This is contrary to the specification of this
210: * method in the {@linkplain java.io.Writer#write(java.lang.String,int,int)
211: * superclass}, which requires that an {@link IndexOutOfBoundsException} be
212: * thrown.
213: *
214: * @param s String to be written
215: * @param off Offset from which to start reading characters
216: * @param len Number of characters to be written
217: *
218: * @exception IOException If an I/O error occurs
219: */
220: public void write(String s, int off, int len) throws IOException {
221: synchronized (lock) {
222: ensureOpen();
223:
224: int b = off, t = off + len;
225: while (b < t) {
226: int d = min(nChars - nextChar, t - b);
227: s.getChars(b, b + d, cb, nextChar);
228: b += d;
229: nextChar += d;
230: if (nextChar >= nChars)
231: flushBuffer();
232: }
233: }
234: }
235:
236: /**
237: * Writes a line separator. The line separator string is defined by the
238: * system property <tt>line.separator</tt>, and is not necessarily a single
239: * newline ('\n') character.
240: *
241: * @exception IOException If an I/O error occurs
242: */
243: public void newLine() throws IOException {
244: write(lineSeparator);
245: }
246:
247: /**
248: * Flushes the stream.
249: *
250: * @exception IOException If an I/O error occurs
251: */
252: public void flush() throws IOException {
253: synchronized (lock) {
254: flushBuffer();
255: out.flush();
256: }
257: }
258:
259: public void close() throws IOException {
260: synchronized (lock) {
261: if (out == null) {
262: return;
263: }
264: try {
265: flushBuffer();
266: } finally {
267: out.close();
268: out = null;
269: cb = null;
270: }
271: }
272: }
273: }
|