001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.io;
019:
020: import java.security.AccessController;
021:
022: import org.apache.harmony.luni.util.Msg;
023: import org.apache.harmony.luni.util.PriviAction;
024:
025: /**
026: * BufferedWriter is for writing buffered character output. Characters written
027: * to this Writer are buffered internally before being committed to the target
028: * Writer.
029: *
030: * @see BufferedReader
031: */
032: public class BufferedWriter extends Writer {
033:
034: private Writer out;
035:
036: private char buf[];
037:
038: private int pos;
039:
040: private final String lineSeparator = AccessController
041: .doPrivileged(new PriviAction<String>("line.separator")); //$NON-NLS-1$
042:
043: /**
044: * Constructs a new BufferedReader with <code>out</code> as the Writer on
045: * which to buffer write operations. The buffer size is set to the default,
046: * which is 8K.
047: *
048: * @param out
049: * The Writer to buffer character writing on
050: */
051: public BufferedWriter(Writer out) {
052: super (out);
053: this .out = out;
054: buf = new char[8192];
055: }
056:
057: /**
058: * Constructs a new BufferedReader with <code>out</code> as the Writer on
059: * which buffer write operations. The buffer size is set to
060: * <code>size</code>.
061: *
062: * @param out
063: * The Writer to buffer character writing on.
064: * @param size
065: * The size of the buffer to use.
066: */
067: public BufferedWriter(Writer out, int size) {
068: super (out);
069: if (size <= 0) {
070: throw new IllegalArgumentException(Msg.getString("K0058")); //$NON-NLS-1$
071: }
072: this .out = out;
073: this .buf = new char[size];
074: }
075:
076: /**
077: * Close this BufferedWriter. The contents of the buffer are flushed, the
078: * target writer is closed, and the buffer is released. Only the first
079: * invocation of close has any effect.
080: *
081: * @throws IOException
082: * If an error occurs attempting to close this Writer.
083: */
084: @Override
085: public void close() throws IOException {
086: synchronized (lock) {
087: if (!isClosed()) {
088: flushInternal();
089: out.close();
090: buf = null;
091: out = null;
092: }
093: }
094: }
095:
096: /**
097: * Flush this BufferedWriter. The contents of the buffer are committed to
098: * the target writer and it is then flushed.
099: *
100: * @throws IOException
101: * If an error occurs attempting to flush this Writer.
102: */
103: @Override
104: public void flush() throws IOException {
105: synchronized (lock) {
106: if (isClosed()) {
107: throw new IOException(Msg.getString("K005d")); //$NON-NLS-1$
108: }
109: flushInternal();
110: out.flush();
111: }
112: }
113:
114: /**
115: * Flushes the internal buffer.
116: */
117: private void flushInternal() throws IOException {
118: if (pos > 0) {
119: out.write(buf, 0, pos);
120: }
121: pos = 0;
122: }
123:
124: /**
125: * Answer a boolean indicating whether or not this BufferedWriter is closed.
126: *
127: * @return <code>true</code> if this reader is closed, <code>false</code>
128: * otherwise
129: */
130: private boolean isClosed() {
131: return out == null;
132: }
133:
134: /**
135: * Write a newline to thie Writer. A newline is determined by the System
136: * property "line.separator". The target writer may or may not be flushed
137: * when a newline is written.
138: *
139: * @throws IOException
140: * If an error occurs attempting to write to this Writer.
141: */
142: public void newLine() throws IOException {
143: write(lineSeparator, 0, lineSeparator.length());
144: }
145:
146: /**
147: * Writes out <code>count</code> characters starting at
148: * <code>offset</code> in <code>buf</code> to this BufferedWriter. If
149: * <code>count</code> is greater than this Writers buffer then flush the
150: * contents and also write the characters directly to the target Writer.
151: *
152: * @param cbuf
153: * the non-null array containing characters to write.
154: * @param offset
155: * offset in buf to retrieve characters
156: * @param count
157: * maximum number of characters to write
158: *
159: * @throws IOException
160: * If this Writer has already been closed or some other
161: * IOException occurs.
162: * @throws IndexOutOfBoundsException
163: * If offset or count are outside of bounds.
164: */
165: @Override
166: public void write(char[] cbuf, int offset, int count)
167: throws IOException {
168: synchronized (lock) {
169: if (isClosed()) {
170: throw new IOException(Msg.getString("K005d")); //$NON-NLS-1$
171: }
172: if (offset < 0 || offset > cbuf.length - count || count < 0) {
173: throw new IndexOutOfBoundsException();
174: }
175: if (pos == 0 && count >= this .buf.length) {
176: out.write(cbuf, offset, count);
177: return;
178: }
179: int available = this .buf.length - pos;
180: if (count < available) {
181: available = count;
182: }
183: if (available > 0) {
184: System
185: .arraycopy(cbuf, offset, this .buf, pos,
186: available);
187: pos += available;
188: }
189: if (pos == this .buf.length) {
190: out.write(this .buf, 0, this .buf.length);
191: pos = 0;
192: if (count > available) {
193: offset += available;
194: available = count - available;
195: if (available >= this .buf.length) {
196: out.write(cbuf, offset, available);
197: return;
198: }
199:
200: System.arraycopy(cbuf, offset, this .buf, pos,
201: available);
202: pos += available;
203: }
204: }
205: }
206: }
207:
208: /**
209: * Writes the character <code>oneChar</code> BufferedWriter. If the buffer
210: * is filled by writing this character, flush this Writer. Only the lower 2
211: * bytes are written.
212: *
213: * @param oneChar
214: * The Character to write out.
215: *
216: * @throws IOException
217: * If this Writer has already been closed or some other
218: * IOException occurs.
219: */
220: @Override
221: public void write(int oneChar) throws IOException {
222: synchronized (lock) {
223: if (isClosed()) {
224: throw new IOException(Msg.getString("K005d")); //$NON-NLS-1$
225: }
226: if (pos >= buf.length) {
227: out.write(buf, 0, buf.length);
228: pos = 0;
229: }
230: buf[pos++] = (char) oneChar;
231: }
232: }
233:
234: /**
235: * Writes out <code>count</code> characters starting at
236: * <code>offset</code> in <code>str</code> to this BufferedWriter. If
237: * <code>count</code> is greater than this Writers buffer then flush the
238: * contents and also write the characters directly to the target Writer.
239: *
240: * @param str
241: * the non-null String containing characters to write
242: * @param offset
243: * offset in str to retrieve characters
244: * @param count
245: * maximum number of characters to write
246: *
247: * @throws IOException
248: * If this Writer has already been closed or some other
249: * IOException occurs.
250: * @throws ArrayIndexOutOfBoundsException
251: * If offset or count are outside of bounds.
252: */
253: @Override
254: public void write(String str, int offset, int count)
255: throws IOException {
256: synchronized (lock) {
257: if (isClosed()) {
258: throw new IOException(Msg.getString("K005d")); //$NON-NLS-1$
259: }
260: if (count <= 0) {
261: return;
262: }
263: if (offset > str.length() - count || offset < 0) {
264: throw new StringIndexOutOfBoundsException();
265: }
266: if (pos == 0 && count >= buf.length) {
267: char[] chars = new char[count];
268: str.getChars(offset, offset + count, chars, 0);
269: out.write(chars, 0, count);
270: return;
271: }
272: int available = buf.length - pos;
273: if (count < available) {
274: available = count;
275: }
276: if (available > 0) {
277: str.getChars(offset, offset + available, buf, pos);
278: pos += available;
279: }
280: if (pos == buf.length) {
281: out.write(this .buf, 0, this .buf.length);
282: pos = 0;
283: if (count > available) {
284: offset += available;
285: available = count - available;
286: if (available >= buf.length) {
287: char[] chars = new char[count];
288: str.getChars(offset, offset + available, chars,
289: 0);
290: out.write(chars, 0, available);
291: return;
292: }
293: str.getChars(offset, offset + available, buf, pos);
294: pos += available;
295: }
296: }
297: }
298: }
299: }
|