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