001: package uk.org.ponder.streamutil;
002:
003: import java.io.BufferedReader;
004: import java.io.ByteArrayInputStream;
005: import java.io.ByteArrayOutputStream;
006: import java.io.FileOutputStream;
007: import java.io.Reader;
008: import java.io.Writer;
009: import java.io.OutputStream;
010: import java.io.InputStream;
011: import java.io.IOException;
012:
013: import uk.org.ponder.stringutil.CharWrap;
014: import uk.org.ponder.stringutil.CharWrapVector;
015: import uk.org.ponder.stringutil.StringList;
016: import uk.org.ponder.util.UniversalRuntimeException;
017:
018: /**
019: * This class contains static utility methods for operating on streams.
020: */
021:
022: public class StreamCopyUtil {
023: /**
024: * A natural buffer size to be used where some significant processing is
025: * applied to streams.
026: */
027: public static final int PROCESS_BUFFER_SIZE = 4096;
028: // a buffer size for internal bulk copying functions
029: private static final int BUF_SIZ = 16384;
030:
031: /**
032: * Copies the supplied input stream to the specified output, closing both
033: * streams on completion or error.
034: *
035: * @param source
036: * The input stream to be copied.
037: * @param dest
038: * The output stream where the input data is to be copied.
039: * @exception IOException
040: * if an I/O error occurs.
041: */
042: public static final void inputToOutput(InputStream source,
043: OutputStream dest, byte[] buffer) {
044: inputToOutput(source, dest, true, true, buffer);
045: }
046:
047: /**
048: * Copies the supplied input stream to the specified output, allowing the user
049: * to specify which of the streams are to be closed on completion or error.
050: *
051: * @param source
052: * The input stream to be copied.
053: * @param dest
054: * The output stream where the input data is to be copied.
055: * @param closeinput
056: * <code>true</code> if the input stream is to be closed on
057: * completion or error.
058: * @param closeoutput
059: * <code>true</code> if the output stream is to be closed on
060: * completion or error.
061: * @exception IOException
062: * if an I/O error occurs.
063: */
064:
065: public static final void inputToOutput(InputStream source,
066: OutputStream dest, boolean closeinput, boolean closeoutput,
067: byte[] buffer) {
068: if (buffer == null)
069: buffer = new byte[BUF_SIZ];
070: long totalbytes = 0;
071: try {
072: while (true) {
073: int bytesread = source.read(buffer);
074:
075: if (bytesread > 0)
076: dest.write(buffer, 0, bytesread);
077: if (bytesread == -1)
078: break;
079: totalbytes += bytesread;
080: }
081: System.out.println("inputToOutput copied " + totalbytes
082: + " bytes");
083: } catch (Throwable t) {
084: throw UniversalRuntimeException.accumulate(t,
085: "Error copying stream after " + totalbytes
086: + " bytes");
087: } finally {
088: if (closeinput)
089: StreamCloseUtil.closeInputStream(source);
090: if (closeoutput)
091: StreamCloseUtil.closeOutputStream(dest);
092: }
093: }
094:
095: /**
096: * Copies the supplied reader to the specified writer, closing both streams on
097: * completion or error.
098: *
099: * @param source
100: * The reader to be copied.
101: * @param dest
102: * The writer where the input data is to be copied.
103: * @exception IOException
104: * if an I/O error occurs.
105: */
106:
107: public static final void readerToWriter(Reader source, Writer dest)
108: throws IOException {
109: char[] buffer = new char[BUF_SIZ];
110: try {
111: while (true) {
112: int charsread = source.read(buffer);
113: if (charsread > 0)
114: dest.write(buffer, 0, charsread);
115: if (charsread == -1)
116: break;
117: }
118: } finally {
119: try {
120: source.close();
121: } finally {
122: dest.close();
123: }
124: }
125: }
126:
127: /*
128: * -- dangerous method relies on platform encoding public static final String
129: * streamToString(InputStream source) throws IOException { return
130: * readerToString (new InputStreamReader(source)); }
131: */
132:
133: /**
134: * A useful utility method to fully read the data from the specified reader
135: * and return it as a string.
136: *
137: * @param source
138: * A reader containing the data to be read. This stream will be
139: * closed on completion or error.
140: * @return A string holding the complete contents read from the reader.
141: * @exception IOException
142: * if an I/O error occurs.
143: */
144:
145: public static final String readerToString(Reader source) {
146: char[] buffer = new char[CharWrap.INITIAL_SIZE];
147: CharWrap build = new CharWrap();
148: try {
149: while (true) {
150: int charsread = source.read(buffer);
151: if (charsread > 0)
152: build.append(buffer, 0, charsread);
153: if (charsread != CharWrap.INITIAL_SIZE)
154: break;
155: }
156: } catch (Exception e) {
157: throw UniversalRuntimeException.accumulate(e,
158: "Error converting Reader to String");
159: } finally {
160: StreamCloseUtil.closeReader(source);
161: }
162: return build.toString();
163: }
164:
165: /** Return \n-delimited data from a reader and return as a list of Strings.
166: * The supplied reader WILL be closed!
167: */
168: public static final StringList readerToStringList(Reader source) {
169: BufferedReader br = new BufferedReader(source);
170: StringList togo = new StringList();
171: try {
172: while (true) {
173: String line = br.readLine();
174: if (line == null)
175: break;
176: togo.add(line);
177: }
178: } catch (Exception t) {
179: throw UniversalRuntimeException.accumulate(t,
180: "Error rendering text as stringlist");
181: } finally {
182: StreamCloseUtil.closeReader(source);
183: }
184: return togo;
185: }
186:
187: /**
188: * Writes the contents of the supplied CharWrapVector to the specified writer,
189: * closing the writer on completion or error.
190: *
191: * @param source
192: * The CharWrapVector to be written
193: * @param dest
194: * The writer where the input data is to be copied.
195: * @exception IOException
196: * if an I/O error occurs.
197: */
198:
199: public static final void charWrapVectorToWriter(
200: CharWrapVector source, Writer dest) throws IOException {
201: for (int i = 0; i < source.size(); ++i) {
202: CharWrap wrap = source.charWrapAt(i);
203: dest.write(wrap.storage, wrap.offset, wrap.size);
204: }
205: }
206:
207: /**
208: * Produces a String representation of the complete contents of the supplied
209: * string, assuming it to be encoded in UTF-8. The supplied stream WILL be
210: * closed.
211: *
212: * @param source
213: * @return
214: */
215: public static String streamToString(InputStream source) {
216: DirectInputStreamReader disr = null;
217: try {
218:
219: disr = new DirectInputStreamReader(source);
220: return readerToString(disr);
221: } catch (Throwable t) {
222: throw UniversalRuntimeException.accumulate(t,
223: "Error converting stream to string");
224: } finally {
225: StreamCloseUtil.closeReader(disr);
226: }
227: }
228:
229: // A debug method which will save a stream to disk and return a copy of
230: // it.
231: public static InputStream bottleToDisk(InputStream is,
232: String filename) {
233: try {
234: ByteArrayOutputStream baos = new ByteArrayOutputStream();
235: inputToOutput(is, baos, new byte[1024]);
236: byte[] buffer = baos.toByteArray();
237: ByteArrayInputStream bais = new ByteArrayInputStream(buffer);
238: FileOutputStream fos = new FileOutputStream(filename);
239: inputToOutput(bais, fos, new byte[1024]);
240: bais = new ByteArrayInputStream(buffer);
241: return bais;
242: } catch (Throwable t) {
243: throw UniversalRuntimeException.accumulate(t,
244: "Error bottling input stream");
245: }
246: }
247: }
|