1. /*
  2. * @(#)BufferedWriter.java 1.26 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.io;
  8. /**
  9. * Write text to a character-output stream, buffering characters so as to
  10. * provide for the efficient writing of single characters, arrays, and strings.
  11. *
  12. * <p> The buffer size may be specified, or the default size may be accepted.
  13. * The default is large enough for most purposes.
  14. *
  15. * <p> A newLine() method is provided, which uses the platform's own notion of
  16. * line separator as defined by the system property <tt>line.separator</tt>.
  17. * Not all platforms use the newline character ('\n') to terminate lines.
  18. * Calling this method to terminate each output line is therefore preferred to
  19. * writing a newline character directly.
  20. *
  21. * <p> In general, a Writer sends its output immediately to the underlying
  22. * character or byte stream. Unless prompt output is required, it is advisable
  23. * to wrap a BufferedWriter around any Writer whose write() operations may be
  24. * costly, such as FileWriters and OutputStreamWriters. For example,
  25. *
  26. * <pre>
  27. * PrintWriter out
  28. * = new PrintWriter(new BufferedWriter(new FileWriter("foo.out")));
  29. * </pre>
  30. *
  31. * will buffer the PrintWriter's output to the file. Without buffering, each
  32. * invocation of a print() method would cause characters to be converted into
  33. * bytes that would then be written immediately to the file, which can be very
  34. * inefficient.
  35. *
  36. * @see PrintWriter
  37. * @see FileWriter
  38. * @see OutputStreamWriter
  39. *
  40. * @version 1.26, 03/12/19
  41. * @author Mark Reinhold
  42. * @since JDK1.1
  43. */
  44. public class BufferedWriter extends Writer {
  45. private Writer out;
  46. private char cb[];
  47. private int nChars, nextChar;
  48. private static int defaultCharBufferSize = 8192;
  49. /**
  50. * Line separator string. This is the value of the line.separator
  51. * property at the moment that the stream was created.
  52. */
  53. private String lineSeparator;
  54. /**
  55. * Create a buffered character-output stream that uses a default-sized
  56. * output buffer.
  57. *
  58. * @param out A Writer
  59. */
  60. public BufferedWriter(Writer out) {
  61. this(out, defaultCharBufferSize);
  62. }
  63. /**
  64. * Create a new buffered character-output stream that uses an output
  65. * buffer of the given size.
  66. *
  67. * @param out A Writer
  68. * @param sz Output-buffer size, a positive integer
  69. *
  70. * @exception IllegalArgumentException If sz is <= 0
  71. */
  72. public BufferedWriter(Writer out, int sz) {
  73. super(out);
  74. if (sz <= 0)
  75. throw new IllegalArgumentException("Buffer size <= 0");
  76. this.out = out;
  77. cb = new char[sz];
  78. nChars = sz;
  79. nextChar = 0;
  80. lineSeparator = (String) java.security.AccessController.doPrivileged(
  81. new sun.security.action.GetPropertyAction("line.separator"));
  82. }
  83. /** Check to make sure that the stream has not been closed */
  84. private void ensureOpen() throws IOException {
  85. if (out == null)
  86. throw new IOException("Stream closed");
  87. }
  88. /**
  89. * Flush the output buffer to the underlying character stream, without
  90. * flushing the stream itself. This method is non-private only so that it
  91. * may be invoked by PrintStream.
  92. */
  93. void flushBuffer() throws IOException {
  94. synchronized (lock) {
  95. ensureOpen();
  96. if (nextChar == 0)
  97. return;
  98. out.write(cb, 0, nextChar);
  99. nextChar = 0;
  100. }
  101. }
  102. /**
  103. * Write a single character.
  104. *
  105. * @exception IOException If an I/O error occurs
  106. */
  107. public void write(int c) throws IOException {
  108. synchronized (lock) {
  109. ensureOpen();
  110. if (nextChar >= nChars)
  111. flushBuffer();
  112. cb[nextChar++] = (char) c;
  113. }
  114. }
  115. /**
  116. * Our own little min method, to avoid loading java.lang.Math if we've run
  117. * out of file descriptors and we're trying to print a stack trace.
  118. */
  119. private int min(int a, int b) {
  120. if (a < b) return a;
  121. return b;
  122. }
  123. /**
  124. * Write a portion of an array of characters.
  125. *
  126. * <p> Ordinarily this method stores characters from the given array into
  127. * this stream's buffer, flushing the buffer to the underlying stream as
  128. * needed. If the requested length is at least as large as the buffer,
  129. * however, then this method will flush the buffer and write the characters
  130. * directly to the underlying stream. Thus redundant
  131. * <code>BufferedWriter</code>s will not copy data unnecessarily.
  132. *
  133. * @param cbuf A character array
  134. * @param off Offset from which to start reading characters
  135. * @param len Number of characters to write
  136. *
  137. * @exception IOException If an I/O error occurs
  138. */
  139. public void write(char cbuf[], int off, int len) throws IOException {
  140. synchronized (lock) {
  141. ensureOpen();
  142. if ((off < 0) || (off > cbuf.length) || (len < 0) ||
  143. ((off + len) > cbuf.length) || ((off + len) < 0)) {
  144. throw new IndexOutOfBoundsException();
  145. } else if (len == 0) {
  146. return;
  147. }
  148. if (len >= nChars) {
  149. /* If the request length exceeds the size of the output buffer,
  150. flush the buffer and then write the data directly. In this
  151. way buffered streams will cascade harmlessly. */
  152. flushBuffer();
  153. out.write(cbuf, off, len);
  154. return;
  155. }
  156. int b = off, t = off + len;
  157. while (b < t) {
  158. int d = min(nChars - nextChar, t - b);
  159. System.arraycopy(cbuf, b, cb, nextChar, d);
  160. b += d;
  161. nextChar += d;
  162. if (nextChar >= nChars)
  163. flushBuffer();
  164. }
  165. }
  166. }
  167. /**
  168. * Write a portion of a String.
  169. *
  170. * <p> If the value of the <tt>len</tt> parameter is negative then no
  171. * characters are written. This is contrary to the specification of this
  172. * method in the {@linkplain java.io.Writer#write(java.lang.String,int,int)
  173. * superclass}, which requires that an {@link IndexOutOfBoundsException} be
  174. * thrown.
  175. *
  176. * @param s String to be written
  177. * @param off Offset from which to start reading characters
  178. * @param len Number of characters to be written
  179. *
  180. * @exception IOException If an I/O error occurs
  181. */
  182. public void write(String s, int off, int len) throws IOException {
  183. synchronized (lock) {
  184. ensureOpen();
  185. int b = off, t = off + len;
  186. while (b < t) {
  187. int d = min(nChars - nextChar, t - b);
  188. s.getChars(b, b + d, cb, nextChar);
  189. b += d;
  190. nextChar += d;
  191. if (nextChar >= nChars)
  192. flushBuffer();
  193. }
  194. }
  195. }
  196. /**
  197. * Write a line separator. The line separator string is defined by the
  198. * system property <tt>line.separator</tt>, and is not necessarily a single
  199. * newline ('\n') character.
  200. *
  201. * @exception IOException If an I/O error occurs
  202. */
  203. public void newLine() throws IOException {
  204. write(lineSeparator);
  205. }
  206. /**
  207. * Flush the stream.
  208. *
  209. * @exception IOException If an I/O error occurs
  210. */
  211. public void flush() throws IOException {
  212. synchronized (lock) {
  213. flushBuffer();
  214. out.flush();
  215. }
  216. }
  217. /**
  218. * Close the stream.
  219. *
  220. * @exception IOException If an I/O error occurs
  221. */
  222. public void close() throws IOException {
  223. synchronized (lock) {
  224. if (out == null)
  225. return;
  226. flushBuffer();
  227. out.close();
  228. out = null;
  229. cb = null;
  230. }
  231. }
  232. }