1 /* 2 * Hunt - A refined core library for D programming language. 3 * 4 * Copyright (C) 2018-2019 HuntLabs 5 * 6 * Website: https://www.huntlabs.net/ 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 12 module hunt.stream.IOUtils; 13 14 import hunt.Exceptions; 15 import hunt.util.Common; 16 import hunt.stream.Common; 17 18 /** 19 * IO Utilities. Provides stream handling utilities in singleton Threadpool 20 * implementation accessed by static members. 21 */ 22 class IOUtils { 23 24 enum string CRLF = "\015\012"; 25 26 enum byte[] CRLF_BYTES = ['\015', '\012']; 27 28 enum int bufferSize = 64 * 1024; 29 30 // static class Job : Runnable { 31 // InputStream input; 32 // OutputStream output; 33 // Reader read; 34 // Writer write; 35 36 // Job(InputStream input, OutputStream output) { 37 // this.input = input; 38 // this.output = output; 39 // this.read = null; 40 // this.write = null; 41 // } 42 43 // Job(Reader read, Writer write) { 44 // this.input = null; 45 // this.output = null; 46 // this.read = read; 47 // this.write = write; 48 // } 49 50 // /* 51 // * @see java.lang.Runnable#run() 52 // */ 53 // void run() { 54 // try { 55 // if (input != null) 56 // copy(input, output, -1); 57 // else 58 // copy(read, write, -1); 59 // } catch (IOException e) { 60 // try { 61 // if (output != null) 62 // output.close(); 63 // if (write != null) 64 // write.close(); 65 // } catch (IOException e2) { 66 67 // } 68 // } 69 // } 70 // } 71 72 /** 73 * Copy Stream input to Stream output until EOF or exception. 74 * 75 * @param input 76 * the input stream to read from (until EOF) 77 * @param output 78 * the output stream to write to 79 * @throws IOException 80 * if unable to copy streams 81 */ 82 static void copy(InputStream input, OutputStream output) { 83 copy(input, output, -1); 84 } 85 86 /** 87 * Copy Reader to Writer output until EOF or exception. 88 * 89 * @param input 90 * the read to read from (until EOF) 91 * @param output 92 * the writer to write to 93 * @throws IOException 94 * if unable to copy the streams 95 */ 96 // static void copy(Reader input, Writer output) { 97 // copy(input, output, -1); 98 // } 99 100 /** 101 * Copy Stream input to Stream for byteCount bytes or until EOF or exception. 102 * 103 * @param input 104 * the stream to read from 105 * @param output 106 * the stream to write to 107 * @param byteCount 108 * the number of bytes to copy 109 * @throws IOException 110 * if unable to copy the streams 111 */ 112 static void copy(InputStream input, OutputStream output, long byteCount) { 113 byte[] buffer = new byte[bufferSize]; 114 int len = bufferSize; 115 116 if (byteCount >= 0) { 117 while (byteCount > 0) { 118 int max = byteCount < bufferSize ? cast(int) byteCount : bufferSize; 119 len = input.read(buffer, 0, max); 120 121 if (len == -1) 122 break; 123 124 byteCount -= len; 125 output.write(buffer, 0, len); 126 } 127 } else { 128 while (true) { 129 len = input.read(buffer, 0, bufferSize); 130 if (len < 0) 131 break; 132 output.write(buffer, 0, len); 133 } 134 } 135 } 136 137 /** 138 * Copy Reader to Writer for byteCount bytes or until EOF or exception. 139 * 140 * @param input 141 * the Reader to read from 142 * @param output 143 * the Writer to write to 144 * @param byteCount 145 * the number of bytes to copy 146 * @throws IOException 147 * if unable to copy streams 148 */ 149 // static void copy(Reader input, Writer output, long byteCount) { 150 // char[] buffer = new char[bufferSize]; 151 // int len = bufferSize; 152 153 // if (byteCount >= 0) { 154 // while (byteCount > 0) { 155 // if (byteCount < bufferSize) 156 // len = input.read(buffer, 0, (int) byteCount); 157 // else 158 // len = input.read(buffer, 0, bufferSize); 159 160 // if (len == -1) 161 // break; 162 163 // byteCount -= len; 164 // output.write(buffer, 0, len); 165 // } 166 // } else if (output instanceof PrintWriter) { 167 // PrintWriter pout = (PrintWriter) output; 168 // while (!pout.checkError()) { 169 // len = input.read(buffer, 0, bufferSize); 170 // if (len == -1) 171 // break; 172 // output.write(buffer, 0, len); 173 // } 174 // } else { 175 // while (true) { 176 // len = input.read(buffer, 0, bufferSize); 177 // if (len == -1) 178 // break; 179 // output.write(buffer, 0, len); 180 // } 181 // } 182 // } 183 184 /** 185 * Copy files or directories 186 * 187 * @param from 188 * the file to copy 189 * @param to 190 * the destination to copy to 191 * @throws IOException 192 * if unable to copy 193 */ 194 // static void copy(File from, File to) { 195 // if (from.isDirectory()) 196 // copyDir(from, to); 197 // else 198 // copyFile(from, to); 199 // } 200 201 // static void copyDir(File from, File to) { 202 // if (to.exists()) { 203 // if (!to.isDirectory()) 204 // throw new IllegalArgumentException(to.toString()); 205 // } else 206 // to.mkdirs(); 207 208 // File[] files = from.listFiles(); 209 // if (files != null) { 210 // for (int i = 0; i < files.length; i++) { 211 // string name = files[i].getName(); 212 // if (".".equals(name) || "..".equals(name)) 213 // continue; 214 // copy(files[i], new File(to, name)); 215 // } 216 // } 217 // } 218 219 // static void copyFile(File from, File to) { 220 // try (InputStream input = new FileInputStream(from); OutputStream output = new FileOutputStream(to)) { 221 // copy(input, output); 222 // } 223 // } 224 225 /** 226 * Read input stream to string. 227 * 228 * @param input 229 * the stream to read from (until EOF) 230 * @return the string parsed from stream (default Charset) 231 * @throws IOException 232 * if unable to read the stream (or handle the charset) 233 */ 234 static string toString(InputStream input) { 235 return toString(input, null); 236 } 237 238 /** 239 * Read input stream to string. 240 * 241 * @param input 242 * the stream to read from (until EOF) 243 * @param encoding 244 * the encoding to use (can be null to use default Charset) 245 * @return the string parsed from the stream 246 * @throws IOException 247 * if unable to read the stream (or handle the charset) 248 */ 249 // static string toString(InputStream input, string encoding) { 250 // return toString(input, encoding == null ? null : Charset.forName(encoding)); 251 // } 252 253 /** 254 * Read input stream to string. 255 * 256 * @param input 257 * the stream to read from (until EOF) 258 * @param encoding 259 * the Charset to use (can be null to use default Charset) 260 * @return the string parsed from the stream 261 * @throws IOException 262 * if unable to read the stream (or handle the charset) 263 */ 264 static string toString(InputStream input, string encoding) { 265 import std.array; 266 Appender!(string) sb; 267 byte[] buffer = new byte[bufferSize]; 268 int len = bufferSize; 269 while (true) { 270 len = input.read(buffer, 0, bufferSize); 271 if (len < 0) 272 break; 273 sb.put(cast(string)buffer[0..len]); 274 } 275 // StringWriter writer = new StringWriter(); 276 // InputStreamReader reader = encoding == null ? new InputStreamReader(input) : new InputStreamReader(input, encoding); 277 278 // copy(reader, writer); 279 return sb.data; 280 } 281 282 /** 283 * Read input stream to string. 284 * 285 * @param input 286 * the reader to read from (until EOF) 287 * @return the string parsed from the reader 288 * @throws IOException 289 * if unable to read the stream (or handle the charset) 290 */ 291 // static string toString(Reader input) { 292 // StringWriter writer = new StringWriter(); 293 // copy(input, writer); 294 // return writer.toString(); 295 // } 296 297 /** 298 * Delete File. This delete will recursively delete directories - BE 299 * CAREFULL 300 * 301 * @param file 302 * The file (or directory) to be deleted. 303 * @return true if anything was deleted. (note: this does not mean that all 304 * content input a directory was deleted) 305 */ 306 // static bool delete(File file) { 307 // if (!file.exists()) 308 // return false; 309 // if (file.isDirectory()) { 310 // File[] files = file.listFiles(); 311 // for (int i = 0; files != null && i < files.length; i++) 312 // delete(files[i]); 313 // } 314 // return file.delete(); 315 // } 316 317 /** 318 * Closes an arbitrary closable, and logs exceptions at ignore level 319 * 320 * @param closeable 321 * the closeable to close 322 */ 323 static void close(Closeable closeable) { 324 try { 325 if (closeable !is null) 326 closeable.close(); 327 } catch (IOException ignore) { 328 } 329 } 330 331 /** 332 * closes an input stream, and logs exceptions 333 * 334 * @param input 335 * the input stream to close 336 */ 337 static void close(InputStream input) { 338 close(cast(Closeable) input); 339 } 340 341 /** 342 * closes an output stream, and logs exceptions 343 * 344 * @param os 345 * the output stream to close 346 */ 347 static void close(OutputStream os) { 348 close(cast(Closeable) os); 349 } 350 351 // /** 352 // * closes a reader, and logs exceptions 353 // * 354 // * @param reader 355 // * the reader to close 356 // */ 357 // static void close(Reader reader) { 358 // close((Closeable) reader); 359 // } 360 361 // /** 362 // * closes a writer, and logs exceptions 363 // * 364 // * @param writer 365 // * the writer to close 366 // */ 367 // static void close(Writer writer) { 368 // close((Closeable) writer); 369 // } 370 371 // static byte[] readBytes(InputStream input) { 372 // ByteArrayOutputStream bout = new ByteArrayOutputStream(); 373 // copy(input, bout); 374 // return bout.toByteArray(); 375 // } 376 377 // /** 378 // * A gathering write utility wrapper. 379 // * <p> 380 // * This method wraps a gather write with a loop that handles the limitations 381 // * of some operating systems that have a limit on the number of buffers 382 // * written. The method loops on the write until either all the content is 383 // * written or no progress is made. 384 // * 385 // * @param output 386 // * The GatheringByteChannel to write to 387 // * @param buffers 388 // * The buffers to write 389 // * @param offset 390 // * The offset into the buffers array 391 // * @param length 392 // * The length input buffers to write 393 // * @return The total bytes written 394 // * @throws IOException 395 // * if unable write to the GatheringByteChannel 396 // */ 397 // static long write(GatheringByteChannel output, ByteBuffer[] buffers, int offset, int length) 398 // throws IOException { 399 // long total = 0; 400 // write: while (length > 0) { 401 // // Write as much as we can 402 // long wrote = output.write(buffers, offset, length); 403 404 // // If we can't write any more, give up 405 // if (wrote == 0) 406 // break; 407 408 // // count the total 409 // total += wrote; 410 411 // // Look for unwritten content 412 // for (int i = offset; i < buffers.length; i++) { 413 // if (buffers[i].hasRemaining()) { 414 // // loop with new offset and length; 415 // length = length - (i - offset); 416 // offset = i; 417 // continue write; 418 // } 419 // } 420 // length = 0; 421 // } 422 423 // return total; 424 // } 425 426 // /** 427 // * @return An outputstream to nowhere 428 // */ 429 // static OutputStream getNullStream() { 430 // return __nullStream; 431 // } 432 433 // /** 434 // * @return An outputstream to nowhere 435 // */ 436 // static InputStream getClosedStream() { 437 // return __closedStream; 438 // } 439 440 // private static class NullOS extends OutputStream { 441 // override 442 // void close() { 443 // } 444 445 // override 446 // void flush() { 447 // } 448 449 // override 450 // void write(byte[] b) { 451 // } 452 453 // override 454 // void write(byte[] b, int i, int l) { 455 // } 456 457 // override 458 // void write(int b) { 459 // } 460 // } 461 462 // private static NullOS __nullStream = new NullOS(); 463 464 // private static class ClosedIS extends InputStream { 465 // override 466 // int read() { 467 // return -1; 468 // } 469 // } 470 471 // private static ClosedIS __closedStream = new ClosedIS(); 472 473 // /** 474 // * @return An writer to nowhere 475 // */ 476 // static Writer getNullWriter() { 477 // return __nullWriter; 478 // } 479 480 // /** 481 // * @return An writer to nowhere 482 // */ 483 // static PrintWriter getNullPrintWriter() { 484 // return __nullPrintWriter; 485 // } 486 487 // private static class NullWrite : Writer { 488 // override 489 // void close() { 490 // } 491 492 // override 493 // void flush() { 494 // } 495 496 // override 497 // void write(char[] b) { 498 // } 499 500 // override 501 // void write(char[] b, int o, int l) { 502 // } 503 504 // override 505 // void write(int b) { 506 // } 507 508 // override 509 // void write(string s) { 510 // } 511 512 // override 513 // void write(string s, int o, int l) { 514 // } 515 // } 516 517 // private static NullWrite __nullWriter = new NullWrite(); 518 // private static PrintWriter __nullPrintWriter = new PrintWriter(__nullWriter); 519 520 }