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