1. /*
  2. * @(#)OutputStreamWriter.java 1.28 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. import sun.io.CharToByteConverter;
  12. import sun.io.ConversionBufferFullException;
  13. /**
  14. * An OutputStreamWriter is a bridge from character streams to byte streams:
  15. * Characters written to it are translated into bytes according to a specified
  16. * <a href="../lang/package-summary.html#charenc">character encoding</a>. The
  17. * encoding that it uses may be specified by name, or the platform's default
  18. * encoding may be accepted.
  19. *
  20. * <p> Each invocation of a write() method causes the encoding converter to be
  21. * invoked on the given character(s). The resulting bytes are accumulated in a
  22. * buffer before being written to the underlying output stream. The size of
  23. * this buffer may be specified, but by default it is large enough for most
  24. * purposes. Note that the characters passed to the write() methods are not
  25. * buffered.
  26. *
  27. * <p> For top efficiency, consider wrapping an OutputStreamWriter within a
  28. * BufferedWriter so as to avoid frequent converter invocations. For example:
  29. *
  30. * <pre>
  31. * Writer out
  32. * = new BufferedWriter(new OutputStreamWriter(System.out));
  33. * </pre>
  34. *
  35. * @see BufferedWriter
  36. * @see OutputStream
  37. * @see <a href="../lang/package-summary.html#charenc">Character encodings</a>
  38. *
  39. * @version 1.28, 02/02/00
  40. * @author Mark Reinhold
  41. * @since JDK1.1
  42. */
  43. public class OutputStreamWriter extends Writer {
  44. private CharToByteConverter ctb;
  45. private OutputStream out;
  46. private static final int defaultByteBufferSize = 8192;
  47. /* bb is a temporary output buffer into which bytes are written. */
  48. private byte bb[];
  49. /* nextByte is where the next byte will be written into bb */
  50. private int nextByte = 0;
  51. /* nBytes is the buffer size = defaultByteBufferSize in this class */
  52. private int nBytes = 0;
  53. /**
  54. * Create an OutputStreamWriter that uses the named character encoding.
  55. *
  56. * @param out An OutputStream
  57. * @param enc The name of a supported
  58. * <a href="../lang/package-summary.html#charenc">character
  59. * encoding</a>
  60. *
  61. * @exception UnsupportedEncodingException
  62. * If the named encoding is not supported
  63. */
  64. public OutputStreamWriter(OutputStream out, String enc)
  65. throws UnsupportedEncodingException
  66. {
  67. this(out, CharToByteConverter.getConverter(enc));
  68. }
  69. /**
  70. * Create an OutputStreamWriter that uses the default character encoding.
  71. *
  72. * @param out An OutputStream
  73. */
  74. public OutputStreamWriter(OutputStream out) {
  75. this(out, CharToByteConverter.getDefault());
  76. }
  77. /**
  78. * Create an OutputStreamWriter that uses the specified character-to-byte
  79. * converter. The converter is assumed to have been reset.
  80. *
  81. * @param out An OutputStream
  82. * @param ctb A CharToByteConverter
  83. */
  84. private OutputStreamWriter(OutputStream out, CharToByteConverter ctb) {
  85. super(out);
  86. if (out == null)
  87. throw new NullPointerException("out is null");
  88. this.out = out;
  89. this.ctb = ctb;
  90. bb = new byte[defaultByteBufferSize];
  91. nBytes = defaultByteBufferSize;
  92. }
  93. /**
  94. * Returns the canonical name of the character encoding being used by this
  95. * stream. If this <code>OutputStreamWriter</code> was created with the
  96. * {@link #OutputStreamWriter(OutputStream, String)} constructor then the
  97. * returned encoding name, being canonical, may differ from the encoding
  98. * name passed to the constructor. May return <code>null</code> if the
  99. * stream has been closed.
  100. *
  101. * @return a String representing the encoding name, or possibly
  102. * <code>null</code> if the stream has been closed
  103. *
  104. * @see <a href="../lang/package-summary.html#charenc">Character
  105. * encodings</a>
  106. */
  107. public String getEncoding() {
  108. synchronized (lock) {
  109. if (ctb != null)
  110. return ctb.getCharacterEncoding();
  111. else
  112. return null;
  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. * Write a single character.
  122. *
  123. * @exception IOException If an I/O error occurs
  124. */
  125. public void write(int c) throws IOException {
  126. char cbuf[] = new char[1];
  127. cbuf[0] = (char) c;
  128. write(cbuf, 0, 1);
  129. }
  130. /**
  131. * Write a portion of an array of characters.
  132. *
  133. * @param cbuf Buffer of characters
  134. * @param off Offset from which to start writing 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. int ci = off, end = off + len;
  149. boolean bufferFlushed = false;
  150. while (ci < end) {
  151. boolean bufferFull = false;
  152. try {
  153. nextByte += ctb.convertAny(cbuf, ci, end,
  154. bb, nextByte, nBytes);
  155. ci = end;
  156. }
  157. catch (ConversionBufferFullException x) {
  158. int nci = ctb.nextCharIndex();
  159. if ((nci == ci) && bufferFlushed) {
  160. /* If the buffer has been flushed and it
  161. still does not hold even one character */
  162. throw new
  163. CharConversionException("Output buffer too small");
  164. }
  165. ci = nci;
  166. bufferFull = true;
  167. nextByte = ctb.nextByteIndex();
  168. }
  169. if ((nextByte >= nBytes) || bufferFull) {
  170. out.write(bb, 0, nextByte);
  171. nextByte = 0;
  172. bufferFlushed = true;
  173. }
  174. }
  175. }
  176. }
  177. /**
  178. * Write a portion of a string.
  179. *
  180. * @param str A String
  181. * @param off Offset from which to start writing characters
  182. * @param len Number of characters to write
  183. *
  184. * @exception IOException If an I/O error occurs
  185. */
  186. public void write(String str, int off, int len) throws IOException {
  187. /* Check the len before creating a char buffer */
  188. if (len < 0)
  189. throw new IndexOutOfBoundsException();
  190. char cbuf[] = new char[len];
  191. str.getChars(off, off + len, cbuf, 0);
  192. write(cbuf, 0, len);
  193. }
  194. /**
  195. * Flush the output buffer to the underlying byte stream, without flushing
  196. * the byte stream itself. This method is non-private only so that it may
  197. * be invoked by PrintStream.
  198. */
  199. void flushBuffer() throws IOException {
  200. synchronized (lock) {
  201. ensureOpen();
  202. for (;;) {
  203. try {
  204. nextByte += ctb.flushAny(bb, nextByte, nBytes);
  205. }
  206. catch (ConversionBufferFullException x) {
  207. nextByte = ctb.nextByteIndex();
  208. }
  209. if (nextByte == 0)
  210. break;
  211. if (nextByte > 0) {
  212. out.write(bb, 0, nextByte);
  213. nextByte = 0;
  214. }
  215. }
  216. }
  217. }
  218. /**
  219. * Flush the stream.
  220. *
  221. * @exception IOException If an I/O error occurs
  222. */
  223. public void flush() throws IOException {
  224. synchronized (lock) {
  225. flushBuffer();
  226. out.flush();
  227. }
  228. }
  229. /**
  230. * Close the stream.
  231. *
  232. * @exception IOException If an I/O error occurs
  233. */
  234. public void close() throws IOException {
  235. synchronized (lock) {
  236. if (out == null)
  237. return;
  238. flush();
  239. out.close();
  240. out = null;
  241. bb = null;
  242. ctb = null;
  243. }
  244. }
  245. }