jaroslav@1258: /* jaroslav@1258: * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. jaroslav@1258: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. jaroslav@1258: * jaroslav@1258: * This code is free software; you can redistribute it and/or modify it jaroslav@1258: * under the terms of the GNU General Public License version 2 only, as jaroslav@1258: * published by the Free Software Foundation. Oracle designates this jaroslav@1258: * particular file as subject to the "Classpath" exception as provided jaroslav@1258: * by Oracle in the LICENSE file that accompanied this code. jaroslav@1258: * jaroslav@1258: * This code is distributed in the hope that it will be useful, but WITHOUT jaroslav@1258: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or jaroslav@1258: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License jaroslav@1258: * version 2 for more details (a copy is included in the LICENSE file that jaroslav@1258: * accompanied this code). jaroslav@1258: * jaroslav@1258: * You should have received a copy of the GNU General Public License version jaroslav@1258: * 2 along with this work; if not, write to the Free Software Foundation, jaroslav@1258: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. jaroslav@1258: * jaroslav@1258: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA jaroslav@1258: * or visit www.oracle.com if you need additional information or have any jaroslav@1258: * questions. jaroslav@1258: */ jaroslav@1258: jaroslav@1258: package java.io; jaroslav@1258: jaroslav@1258: jaroslav@1258: /** jaroslav@1258: * Writes text to a character-output stream, buffering characters so as to jaroslav@1258: * provide for the efficient writing of single characters, arrays, and strings. jaroslav@1258: * jaroslav@1258: *

The buffer size may be specified, or the default size may be accepted. jaroslav@1258: * The default is large enough for most purposes. jaroslav@1258: * jaroslav@1258: *

A newLine() method is provided, which uses the platform's own notion of jaroslav@1258: * line separator as defined by the system property line.separator. jaroslav@1258: * Not all platforms use the newline character ('\n') to terminate lines. jaroslav@1258: * Calling this method to terminate each output line is therefore preferred to jaroslav@1258: * writing a newline character directly. jaroslav@1258: * jaroslav@1258: *

In general, a Writer sends its output immediately to the underlying jaroslav@1258: * character or byte stream. Unless prompt output is required, it is advisable jaroslav@1258: * to wrap a BufferedWriter around any Writer whose write() operations may be jaroslav@1258: * costly, such as FileWriters and OutputStreamWriters. For example, jaroslav@1258: * jaroslav@1258: *

jaroslav@1258:  * PrintWriter out
jaroslav@1258:  *   = new PrintWriter(new BufferedWriter(new FileWriter("foo.out")));
jaroslav@1258:  * 
jaroslav@1258: * jaroslav@1258: * will buffer the PrintWriter's output to the file. Without buffering, each jaroslav@1258: * invocation of a print() method would cause characters to be converted into jaroslav@1258: * bytes that would then be written immediately to the file, which can be very jaroslav@1258: * inefficient. jaroslav@1258: * jaroslav@1258: * @see PrintWriter jaroslav@1258: * @see FileWriter jaroslav@1258: * @see OutputStreamWriter jaroslav@1258: * @see java.nio.file.Files#newBufferedWriter jaroslav@1258: * jaroslav@1258: * @author Mark Reinhold jaroslav@1258: * @since JDK1.1 jaroslav@1258: */ jaroslav@1258: jaroslav@1258: public class BufferedWriter extends Writer { jaroslav@1258: jaroslav@1258: private Writer out; jaroslav@1258: jaroslav@1258: private char cb[]; jaroslav@1258: private int nChars, nextChar; jaroslav@1258: jaroslav@1258: private static int defaultCharBufferSize = 8192; jaroslav@1258: jaroslav@1258: /** jaroslav@1258: * Line separator string. This is the value of the line.separator jaroslav@1258: * property at the moment that the stream was created. jaroslav@1258: */ jaroslav@1258: private String lineSeparator; jaroslav@1258: jaroslav@1258: /** jaroslav@1258: * Creates a buffered character-output stream that uses a default-sized jaroslav@1258: * output buffer. jaroslav@1258: * jaroslav@1258: * @param out A Writer jaroslav@1258: */ jaroslav@1258: public BufferedWriter(Writer out) { jaroslav@1258: this(out, defaultCharBufferSize); jaroslav@1258: } jaroslav@1258: jaroslav@1258: /** jaroslav@1258: * Creates a new buffered character-output stream that uses an output jaroslav@1258: * buffer of the given size. jaroslav@1258: * jaroslav@1258: * @param out A Writer jaroslav@1258: * @param sz Output-buffer size, a positive integer jaroslav@1258: * jaroslav@1258: * @exception IllegalArgumentException If sz is <= 0 jaroslav@1258: */ jaroslav@1258: public BufferedWriter(Writer out, int sz) { jaroslav@1258: super(out); jaroslav@1258: if (sz <= 0) jaroslav@1258: throw new IllegalArgumentException("Buffer size <= 0"); jaroslav@1258: this.out = out; jaroslav@1258: cb = new char[sz]; jaroslav@1258: nChars = sz; jaroslav@1258: nextChar = 0; jaroslav@1258: jaroslav@1258: lineSeparator = java.security.AccessController.doPrivileged( jaroslav@1258: new sun.security.action.GetPropertyAction("line.separator")); jaroslav@1258: } jaroslav@1258: jaroslav@1258: /** Checks to make sure that the stream has not been closed */ jaroslav@1258: private void ensureOpen() throws IOException { jaroslav@1258: if (out == null) jaroslav@1258: throw new IOException("Stream closed"); jaroslav@1258: } jaroslav@1258: jaroslav@1258: /** jaroslav@1258: * Flushes the output buffer to the underlying character stream, without jaroslav@1258: * flushing the stream itself. This method is non-private only so that it jaroslav@1258: * may be invoked by PrintStream. jaroslav@1258: */ jaroslav@1258: void flushBuffer() throws IOException { jaroslav@1258: synchronized (lock) { jaroslav@1258: ensureOpen(); jaroslav@1258: if (nextChar == 0) jaroslav@1258: return; jaroslav@1258: out.write(cb, 0, nextChar); jaroslav@1258: nextChar = 0; jaroslav@1258: } jaroslav@1258: } jaroslav@1258: jaroslav@1258: /** jaroslav@1258: * Writes a single character. jaroslav@1258: * jaroslav@1258: * @exception IOException If an I/O error occurs jaroslav@1258: */ jaroslav@1258: public void write(int c) throws IOException { jaroslav@1258: synchronized (lock) { jaroslav@1258: ensureOpen(); jaroslav@1258: if (nextChar >= nChars) jaroslav@1258: flushBuffer(); jaroslav@1258: cb[nextChar++] = (char) c; jaroslav@1258: } jaroslav@1258: } jaroslav@1258: jaroslav@1258: /** jaroslav@1258: * Our own little min method, to avoid loading java.lang.Math if we've run jaroslav@1258: * out of file descriptors and we're trying to print a stack trace. jaroslav@1258: */ jaroslav@1258: private int min(int a, int b) { jaroslav@1258: if (a < b) return a; jaroslav@1258: return b; jaroslav@1258: } jaroslav@1258: jaroslav@1258: /** jaroslav@1258: * Writes a portion of an array of characters. jaroslav@1258: * jaroslav@1258: *

Ordinarily this method stores characters from the given array into jaroslav@1258: * this stream's buffer, flushing the buffer to the underlying stream as jaroslav@1258: * needed. If the requested length is at least as large as the buffer, jaroslav@1258: * however, then this method will flush the buffer and write the characters jaroslav@1258: * directly to the underlying stream. Thus redundant jaroslav@1258: * BufferedWriters will not copy data unnecessarily. jaroslav@1258: * jaroslav@1258: * @param cbuf A character array jaroslav@1258: * @param off Offset from which to start reading characters jaroslav@1258: * @param len Number of characters to write jaroslav@1258: * jaroslav@1258: * @exception IOException If an I/O error occurs jaroslav@1258: */ jaroslav@1258: public void write(char cbuf[], int off, int len) throws IOException { jaroslav@1258: synchronized (lock) { jaroslav@1258: ensureOpen(); jaroslav@1258: if ((off < 0) || (off > cbuf.length) || (len < 0) || jaroslav@1258: ((off + len) > cbuf.length) || ((off + len) < 0)) { jaroslav@1258: throw new IndexOutOfBoundsException(); jaroslav@1258: } else if (len == 0) { jaroslav@1258: return; jaroslav@1258: } jaroslav@1258: jaroslav@1258: if (len >= nChars) { jaroslav@1258: /* If the request length exceeds the size of the output buffer, jaroslav@1258: flush the buffer and then write the data directly. In this jaroslav@1258: way buffered streams will cascade harmlessly. */ jaroslav@1258: flushBuffer(); jaroslav@1258: out.write(cbuf, off, len); jaroslav@1258: return; jaroslav@1258: } jaroslav@1258: jaroslav@1258: int b = off, t = off + len; jaroslav@1258: while (b < t) { jaroslav@1258: int d = min(nChars - nextChar, t - b); jaroslav@1258: System.arraycopy(cbuf, b, cb, nextChar, d); jaroslav@1258: b += d; jaroslav@1258: nextChar += d; jaroslav@1258: if (nextChar >= nChars) jaroslav@1258: flushBuffer(); jaroslav@1258: } jaroslav@1258: } jaroslav@1258: } jaroslav@1258: jaroslav@1258: /** jaroslav@1258: * Writes a portion of a String. jaroslav@1258: * jaroslav@1258: *

If the value of the len parameter is negative then no jaroslav@1258: * characters are written. This is contrary to the specification of this jaroslav@1258: * method in the {@linkplain java.io.Writer#write(java.lang.String,int,int) jaroslav@1258: * superclass}, which requires that an {@link IndexOutOfBoundsException} be jaroslav@1258: * thrown. jaroslav@1258: * jaroslav@1258: * @param s String to be written jaroslav@1258: * @param off Offset from which to start reading characters jaroslav@1258: * @param len Number of characters to be written jaroslav@1258: * jaroslav@1258: * @exception IOException If an I/O error occurs jaroslav@1258: */ jaroslav@1258: public void write(String s, int off, int len) throws IOException { jaroslav@1258: synchronized (lock) { jaroslav@1258: ensureOpen(); jaroslav@1258: jaroslav@1258: int b = off, t = off + len; jaroslav@1258: while (b < t) { jaroslav@1258: int d = min(nChars - nextChar, t - b); jaroslav@1258: s.getChars(b, b + d, cb, nextChar); jaroslav@1258: b += d; jaroslav@1258: nextChar += d; jaroslav@1258: if (nextChar >= nChars) jaroslav@1258: flushBuffer(); jaroslav@1258: } jaroslav@1258: } jaroslav@1258: } jaroslav@1258: jaroslav@1258: /** jaroslav@1258: * Writes a line separator. The line separator string is defined by the jaroslav@1258: * system property line.separator, and is not necessarily a single jaroslav@1258: * newline ('\n') character. jaroslav@1258: * jaroslav@1258: * @exception IOException If an I/O error occurs jaroslav@1258: */ jaroslav@1258: public void newLine() throws IOException { jaroslav@1258: write(lineSeparator); jaroslav@1258: } jaroslav@1258: jaroslav@1258: /** jaroslav@1258: * Flushes the stream. jaroslav@1258: * jaroslav@1258: * @exception IOException If an I/O error occurs jaroslav@1258: */ jaroslav@1258: public void flush() throws IOException { jaroslav@1258: synchronized (lock) { jaroslav@1258: flushBuffer(); jaroslav@1258: out.flush(); jaroslav@1258: } jaroslav@1258: } jaroslav@1258: jaroslav@1258: public void close() throws IOException { jaroslav@1258: synchronized (lock) { jaroslav@1258: if (out == null) { jaroslav@1258: return; jaroslav@1258: } jaroslav@1258: try { jaroslav@1258: flushBuffer(); jaroslav@1258: } finally { jaroslav@1258: out.close(); jaroslav@1258: out = null; jaroslav@1258: cb = null; jaroslav@1258: } jaroslav@1258: } jaroslav@1258: } jaroslav@1258: }