View Javadoc
1   //******************************************************************************
2   //
3   // File:    LineBufferedOutputStream.java
4   // Package: edu.rit.io
5   // Unit:    Class edu.rit.io.LineBufferedOutputStream
6   //
7   // This Java source file is copyright (C) 2006 by Alan Kaminsky. All rights
8   // reserved. For further information, contact the author, Alan Kaminsky, at
9   // ark@cs.rit.edu.
10  //
11  // This Java source file is part of the Parallel Java Library ("PJ"). PJ is free
12  // software; you can redistribute it and/or modify it under the terms of the GNU
13  // General Public License as published by the Free Software Foundation; either
14  // version 3 of the License, or (at your option) any later version.
15  //
16  // PJ is distributed in the hope that it will be useful, but WITHOUT ANY
17  // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
18  // A PARTICULAR PURPOSE. See the GNU General Public License for more details.
19  //
20  // Linking this library statically or dynamically with other modules is making a
21  // combined work based on this library. Thus, the terms and conditions of the GNU
22  // General Public License cover the whole combination.
23  //
24  // As a special exception, the copyright holders of this library give you
25  // permission to link this library with independent modules to produce an
26  // executable, regardless of the license terms of these independent modules, and
27  // to copy and distribute the resulting executable under terms of your choice,
28  // provided that you also meet, for each linked independent module, the terms
29  // and conditions of the license of that module. An independent module is a module
30  // which is not derived from or based on this library. If you modify this library,
31  // you may extend this exception to your version of the library, but you are not
32  // obligated to do so. If you do not wish to do so, delete this exception
33  // statement from your version.
34  //
35  // A copy of the GNU General Public License is provided in the file gpl.txt. You
36  // may also obtain a copy of the GNU General Public License on the World Wide
37  // Web at http://www.gnu.org/licenses/gpl.html.
38  //
39  //******************************************************************************
40  package edu.rit.io;
41  
42  import java.io.ByteArrayOutputStream;
43  import java.io.FilterOutputStream;
44  import java.io.IOException;
45  import java.io.OutputStream;
46  
47  /**
48   * Class LineBufferedOutputStream provides a line buffer layered on top of an
49   * underlying output stream. All writes to the line buffered output stream are
50   * accumulated in an internal buffer. Calling <code>flush()</code> on the line
51   * buffered output stream does nothing. The only times the internal buffer is
52   * flushed to the underlying output stream are when a newline byte
53   * (<code>'\n'</code>) is written and when the line buffered output stream is
54   * closed.
55   *
56   * @author Alan Kaminsky
57   * @version 19-Oct-2006
58   */
59  public class LineBufferedOutputStream
60          extends FilterOutputStream {
61  
62  // Hidden data members.
63      private ByteArrayOutputStream buffer = new ByteArrayOutputStream();
64  
65  // Exported constructors.
66      /**
67       * Construct a new line buffered output stream.
68       *
69       * @param out Underlying output stream.
70       */
71      public LineBufferedOutputStream(OutputStream out) {
72          super(out);
73      }
74  
75  // Exported operations.
76      /**
77       * Write the given byte to this line buffered output stream. Only the least
78       * significant 8 bits of <code>b</code> are written.
79       *
80       * @param b Byte.
81       * @exception IOException Thrown if an I/O error occurred.
82       * @throws java.io.IOException if any.
83       */
84      public void write(int b)
85              throws IOException {
86          buffer.write(b);
87          if (b == '\n') {
88              flushBuffer();
89          }
90      }
91  
92      /**
93       * Write the given byte array to this line buffered output stream.
94       *
95       * @param buf Byte array.
96       * @exception NullPointerException (unchecked exception) Thrown if
97       * <code>buf</code> is null.
98       * @exception IOException Thrown if an I/O error occurred.
99       * @throws java.io.IOException if any.
100      */
101     public void write(byte[] buf)
102             throws IOException {
103         write(buf, 0, buf.length);
104     }
105 
106     /**
107      * {@inheritDoc}
108      *
109      * Write a portion of the given byte array to this line buffered output
110      * stream.
111      * @exception NullPointerException (unchecked exception) Thrown if
112      * <code>buf</code> is null.
113      * @exception IndexOutOfBoundsException (unchecked exception) Thrown if
114      * <code>off</code> &lt; 0, <code>len</code>
115      * &lt; 0, or <code>off+len</code> &gt; <code>buf.length</code>.
116      * @exception IOException Thrown if an I/O error occurred.
117      */
118     public void write(byte[] buf,
119             int off,
120             int len)
121             throws IOException {
122         if (off < 0 || len < 0 || off + len > buf.length) {
123             throw new IndexOutOfBoundsException();
124         }
125         while (len > 0) {
126             int i = findNewlineIndex(buf, off, len);
127             if (i == off + len) {
128                 buffer.write(buf, off, len);
129                 off += len;
130                 len = 0;
131             } else {
132                 int n = i - off + 1;
133                 buffer.write(buf, off, n);
134                 flushBuffer();
135                 off += n;
136                 len -= n;
137             }
138         }
139     }
140 
141     /**
142      * Flush this line buffered output stream. The <code>flush()</code> method does
143      * nothing.
144      *
145      * @exception IOException Thrown if an I/O error occurred.
146      * @throws java.io.IOException if any.
147      */
148     public void flush()
149             throws IOException {
150     }
151 
152     /**
153      * Close this line buffered output stream.
154      *
155      * @exception IOException Thrown if an I/O error occurred.
156      * @throws java.io.IOException if any.
157      */
158     public void close()
159             throws IOException {
160         try {
161             flushBuffer();
162             out.close();
163         } finally {
164             buffer = null;
165             out = null;
166         }
167     }
168 
169 // Hidden operations.
170     /**
171      * Flush the line buffer to the underlying output stream.
172      *
173      * @exception IOException Thrown if an I/O error occurred.
174      */
175     private void flushBuffer()
176             throws IOException {
177         buffer.writeTo(out);
178         buffer.reset();
179     }
180 
181     /**
182      * Find the next newline in the given byte array.
183      *
184      * @param buf Byte array.
185      * @param off Index of first byte to look at.
186      * @param len Number of bytes to look at.
187      *
188      * @return Index of first newline at or after index <code>off</code>, or
189      * <code>off+len</code> if there is no newline.
190      */
191     private int findNewlineIndex(byte[] buf,
192             int off,
193             int len) {
194         while (len > 0 && buf[off] != '\n') {
195             ++off;
196             --len;
197         }
198         return off;
199     }
200 
201 }