001package com.randomnoun.common; 002 003/* (c) 2013 randomnoun. All Rights Reserved. This work is licensed under a 004 * BSD Simplified License. (http://www.randomnoun.com/bsd-simplified.html) 005 */ 006 007import java.io.*; 008 009 010/** 011 * Utility class to copy streams synchronously and asynchronously. 012 * 013 * 014 * @author knoxg 015 */ 016public class StreamUtil { 017 018 019 /** 020 * Creates a new StreamUtils object. 021 */ 022 public StreamUtil() { 023 } 024 025 /** Copies the data from an inputStream to an outputstream (used to mimic 026 * pipes). 027 * 028 * @param input The stream to retrieve information from 029 * @param output The stream to send data to 030 * @param bufSize buffer size in bytes 031 * 032 * @throws IOException 033 */ 034 public static void copyStream(InputStream input, OutputStream output, int bufSize) 035 throws IOException { 036 int bytesRead; 037 byte[] buffer = new byte[bufSize]; 038 039 while ((bytesRead = input.read(buffer)) != -1) { 040 output.write(buffer, 0, bytesRead); 041 output.flush(); 042 } 043 } 044 045 /** Copies a stream and return number of bytes copied 046 * 047 * @param input The stream to retrieve information from 048 * @param output The stream to send data to 049 * @param bufSize buffer size in bytes 050 * 051 * @throws IOException 052 */ 053 public static long copyStreamCount(InputStream input, OutputStream output, int bufSize) 054 throws IOException 055 { 056 long totalBytes = 0; 057 int bytesRead; 058 byte[] buffer = new byte[bufSize]; 059 060 while ((bytesRead = input.read(buffer)) != -1) { 061 output.write(buffer, 0, bytesRead); 062 output.flush(); 063 totalBytes += bytesRead; 064 } 065 return totalBytes; 066 } 067 068 069 /** Copies the data from an inputStream to an outputstream 070 * 071 * @param input The stream to retrieve information from 072 * @param output The stream to send data to 073 * 074 * @throws IOException 075 */ 076 public static void copyStream(InputStream input, OutputStream output) 077 throws IOException 078 { 079 copyStream(input, output, 4096); 080 } 081 082 /** Reads all available data from an InputStream, and returns it in a 083 * single byte array. 084 * 085 * @param input The stream to receive information from 086 * @return A byte array containing the contents of the stream 087 * @throws IOException 088 */ 089 public static byte[] getByteArray(InputStream input) 090 throws IOException { 091 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 092 093 copyStream(input, baos, 1024); 094 095 return baos.toByteArray(); 096 } 097 098 /** Returns a thread that, when started, will pipe all data from one 099 * inputstream to an outputstream. The thread will complete when the 100 * inputStream returns EOF. 101 * 102 * @param input The stream to retrieve information from 103 * @param output The stream to send data to 104 * @param bufSize buffer size in bytes 105 */ 106 public static Thread copyThread(InputStream input, OutputStream output, int bufSize) { 107 // not terribly sure why variables accessed from within anonymous classes 108 // need to be final, but hey. Hopefully this is just final within the 109 // scope of this method call. Which would make sense. 110 final InputStream f_input = input; 111 final OutputStream f_output = output; 112 final int f_bufSize = bufSize; 113 114 return new Thread() { 115 public void run() { 116 try { 117 copyStream(f_input, f_output, f_bufSize); 118 } catch (IOException e) { 119 // not much we can do about this, unfortunately. 120 // could wrap in a runtime exception, I guess. 121 // yeah, let's do that. 122 throw new RuntimeException(e); 123 } 124 } 125 }; 126 } 127 128 /** Scans this input stream until the text in 'searchText' is found. Returns 129 * the number of bytes skipped if the search text was found, or -1 if the text 130 * was not found. 131 * 132 * @param input The input stream to scan 133 * @param searchText The text we are searching for 134 * 135 * @throws IOException if an IO Exception occurs reading the stream 136 */ 137 public static int indexOf(InputStream input, String searchText) throws IOException { 138 int bytesRead = 0; 139 int matched = 0; 140 int ch; 141 byte[] compare = searchText.getBytes(); 142 int compareSize = compare.length; 143 while (true) { 144 ch = input.read(); 145 if (ch==-1) { return -1; } 146 bytesRead++; 147 if (ch==compare[matched]) { 148 matched++; 149 if (matched==compareSize) { 150 return bytesRead; 151 } 152 } else { 153 matched = 0; 154 } 155 } 156 } 157 158 /** Reads this input stream until the text in 'searchText' is found. Returns 159 * a String containing the data read, including the searchText. Returns null if the text 160 * was not found. 161 * 162 * @param input The input stream to scan 163 * @param searchText The text we are searching for 164 * 165 * @throws IOException if an IO Exception occurs reading the stream 166 */ 167 public static String readUntil(InputStream input, String searchText) throws IOException { 168 //int bytesRead = 0; 169 int matched = 0; 170 int ch; 171 byte[] compare = searchText.getBytes(); 172 int compareSize = compare.length; 173 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 174 while (true) { 175 ch = input.read(); 176 if (ch==-1) { return null; } 177 //bytesRead++; 178 baos.write(ch); 179 if (ch==compare[matched]) { 180 matched++; 181 if (matched==compareSize) { 182 return baos.toString(); 183 } 184 } else { 185 matched = 0; 186 } 187 } 188 } 189 190 /** Returns a thread that, when started, will pipe all data from one 191 * inputstream to an outputstream. The thread will complete when the 192 * inputStream returns EOF. The output stream will also be closed. 193 * 194 * @param input The stream to retrieve information from 195 * @param output The stream to send data to 196 * @param bufSize buffer size in bytes 197 */ 198 public static Thread copyAndCloseThread(InputStream input, OutputStream output, int bufSize) { 199 // not terribly sure why variables accessed from within anonymous classes 200 // need to be final, but hey. Hopefully this is just final within the 201 // scope of this method call. Which would make sense. 202 final InputStream f_input = input; 203 final OutputStream f_output = output; 204 final int f_bufSize = bufSize; 205 206 return new Thread() { 207 public void run() { 208 try { 209 copyStream(f_input, f_output, f_bufSize); 210 f_output.close(); 211 } catch (IOException e) { 212 // not much we can do about this, unfortunately. 213 // could wrap in a runtime exception, I guess. 214 // yeah, let's do that. 215 throw new RuntimeException(e); 216 } 217 } 218 }; 219 } 220 221 222 223}