001/* 002 * Copyright (C) 2007 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.google.common.io; 018 019import static com.google.common.base.Preconditions.checkArgument; 020import static com.google.common.base.Preconditions.checkNotNull; 021import static com.google.common.base.Preconditions.checkPositionIndex; 022 023import com.google.common.annotations.Beta; 024import com.google.common.base.Function; 025import com.google.common.collect.Iterables; 026import com.google.common.hash.HashCode; 027import com.google.common.hash.HashFunction; 028 029import java.io.ByteArrayInputStream; 030import java.io.ByteArrayOutputStream; 031import java.io.DataInput; 032import java.io.DataInputStream; 033import java.io.DataOutput; 034import java.io.DataOutputStream; 035import java.io.EOFException; 036import java.io.FilterInputStream; 037import java.io.IOException; 038import java.io.InputStream; 039import java.io.OutputStream; 040import java.nio.ByteBuffer; 041import java.nio.channels.ReadableByteChannel; 042import java.nio.channels.WritableByteChannel; 043import java.util.Arrays; 044 045/** 046 * Provides utility methods for working with byte arrays and I/O streams. 047 * 048 * @author Chris Nokleberg 049 * @author Colin Decker 050 * @since 1.0 051 */ 052@Beta 053public final class ByteStreams { 054 private static final int BUF_SIZE = 0x1000; // 4K 055 056 private ByteStreams() {} 057 058 /** 059 * Returns a factory that will supply instances of 060 * {@link ByteArrayInputStream} that read from the given byte array. 061 * 062 * @param b the input buffer 063 * @return the factory 064 */ 065 public static InputSupplier<ByteArrayInputStream> newInputStreamSupplier( 066 byte[] b) { 067 return asInputSupplier(ByteSource.wrap(b)); 068 } 069 070 /** 071 * Returns a factory that will supply instances of 072 * {@link ByteArrayInputStream} that read from the given byte array. 073 * 074 * @param b the input buffer 075 * @param off the offset in the buffer of the first byte to read 076 * @param len the maximum number of bytes to read from the buffer 077 * @return the factory 078 */ 079 public static InputSupplier<ByteArrayInputStream> newInputStreamSupplier( 080 final byte[] b, final int off, final int len) { 081 return asInputSupplier(ByteSource.wrap(b).slice(off, len)); 082 } 083 084 /** 085 * Returns a new {@link ByteSource} that reads bytes from the given byte array. 086 * 087 * @since 14.0 088 * @deprecated Use {@link ByteSource#wrap(byte[])} instead. This method is 089 * scheduled to be removed in Guava 16.0. 090 */ 091 @Deprecated 092 public static ByteSource asByteSource(byte[] b) { 093 return ByteSource.wrap(b); 094 } 095 096 /** 097 * Writes a byte array to an output stream from the given supplier. 098 * 099 * @param from the bytes to write 100 * @param to the output supplier 101 * @throws IOException if an I/O error occurs 102 */ 103 public static void write(byte[] from, 104 OutputSupplier<? extends OutputStream> to) throws IOException { 105 asByteSink(to).write(from); 106 } 107 108 /** 109 * Opens input and output streams from the given suppliers, copies all 110 * bytes from the input to the output, and closes the streams. 111 * 112 * @param from the input factory 113 * @param to the output factory 114 * @return the number of bytes copied 115 * @throws IOException if an I/O error occurs 116 */ 117 public static long copy(InputSupplier<? extends InputStream> from, 118 OutputSupplier<? extends OutputStream> to) throws IOException { 119 return asByteSource(from).copyTo(asByteSink(to)); 120 } 121 122 /** 123 * Opens an input stream from the supplier, copies all bytes from the 124 * input to the output, and closes the input stream. Does not close 125 * or flush the output stream. 126 * 127 * @param from the input factory 128 * @param to the output stream to write to 129 * @return the number of bytes copied 130 * @throws IOException if an I/O error occurs 131 */ 132 public static long copy(InputSupplier<? extends InputStream> from, 133 OutputStream to) throws IOException { 134 return asByteSource(from).copyTo(to); 135 } 136 137 /** 138 * Opens an output stream from the supplier, copies all bytes from the input 139 * to the output, and closes the output stream. Does not close or flush the 140 * input stream. 141 * 142 * @param from the input stream to read from 143 * @param to the output factory 144 * @return the number of bytes copied 145 * @throws IOException if an I/O error occurs 146 * @since 10.0 147 */ 148 public static long copy(InputStream from, 149 OutputSupplier<? extends OutputStream> to) throws IOException { 150 return asByteSink(to).writeFrom(from); 151 } 152 153 /** 154 * Copies all bytes from the input stream to the output stream. 155 * Does not close or flush either stream. 156 * 157 * @param from the input stream to read from 158 * @param to the output stream to write to 159 * @return the number of bytes copied 160 * @throws IOException if an I/O error occurs 161 */ 162 public static long copy(InputStream from, OutputStream to) 163 throws IOException { 164 checkNotNull(from); 165 checkNotNull(to); 166 byte[] buf = new byte[BUF_SIZE]; 167 long total = 0; 168 while (true) { 169 int r = from.read(buf); 170 if (r == -1) { 171 break; 172 } 173 to.write(buf, 0, r); 174 total += r; 175 } 176 return total; 177 } 178 179 /** 180 * Copies all bytes from the readable channel to the writable channel. 181 * Does not close or flush either channel. 182 * 183 * @param from the readable channel to read from 184 * @param to the writable channel to write to 185 * @return the number of bytes copied 186 * @throws IOException if an I/O error occurs 187 */ 188 public static long copy(ReadableByteChannel from, 189 WritableByteChannel to) throws IOException { 190 checkNotNull(from); 191 checkNotNull(to); 192 ByteBuffer buf = ByteBuffer.allocate(BUF_SIZE); 193 long total = 0; 194 while (from.read(buf) != -1) { 195 buf.flip(); 196 while (buf.hasRemaining()) { 197 total += to.write(buf); 198 } 199 buf.clear(); 200 } 201 return total; 202 } 203 204 /** 205 * Reads all bytes from an input stream into a byte array. 206 * Does not close the stream. 207 * 208 * @param in the input stream to read from 209 * @return a byte array containing all the bytes from the stream 210 * @throws IOException if an I/O error occurs 211 */ 212 public static byte[] toByteArray(InputStream in) throws IOException { 213 ByteArrayOutputStream out = new ByteArrayOutputStream(); 214 copy(in, out); 215 return out.toByteArray(); 216 } 217 218 /** 219 * Returns the data from a {@link InputStream} factory as a byte array. 220 * 221 * @param supplier the factory 222 * @throws IOException if an I/O error occurs 223 */ 224 public static byte[] toByteArray( 225 InputSupplier<? extends InputStream> supplier) throws IOException { 226 return asByteSource(supplier).read(); 227 } 228 229 /** 230 * Returns a new {@link ByteArrayDataInput} instance to read from the {@code 231 * bytes} array from the beginning. 232 */ 233 public static ByteArrayDataInput newDataInput(byte[] bytes) { 234 return new ByteArrayDataInputStream(bytes); 235 } 236 237 /** 238 * Returns a new {@link ByteArrayDataInput} instance to read from the {@code 239 * bytes} array, starting at the given position. 240 * 241 * @throws IndexOutOfBoundsException if {@code start} is negative or greater 242 * than the length of the array 243 */ 244 public static ByteArrayDataInput newDataInput(byte[] bytes, int start) { 245 checkPositionIndex(start, bytes.length); 246 return new ByteArrayDataInputStream(bytes, start); 247 } 248 249 private static class ByteArrayDataInputStream implements ByteArrayDataInput { 250 final DataInput input; 251 252 ByteArrayDataInputStream(byte[] bytes) { 253 this.input = new DataInputStream(new ByteArrayInputStream(bytes)); 254 } 255 256 ByteArrayDataInputStream(byte[] bytes, int start) { 257 this.input = new DataInputStream( 258 new ByteArrayInputStream(bytes, start, bytes.length - start)); 259 } 260 261 @Override public void readFully(byte b[]) { 262 try { 263 input.readFully(b); 264 } catch (IOException e) { 265 throw new IllegalStateException(e); 266 } 267 } 268 269 @Override public void readFully(byte b[], int off, int len) { 270 try { 271 input.readFully(b, off, len); 272 } catch (IOException e) { 273 throw new IllegalStateException(e); 274 } 275 } 276 277 @Override public int skipBytes(int n) { 278 try { 279 return input.skipBytes(n); 280 } catch (IOException e) { 281 throw new IllegalStateException(e); 282 } 283 } 284 285 @Override public boolean readBoolean() { 286 try { 287 return input.readBoolean(); 288 } catch (IOException e) { 289 throw new IllegalStateException(e); 290 } 291 } 292 293 @Override public byte readByte() { 294 try { 295 return input.readByte(); 296 } catch (EOFException e) { 297 throw new IllegalStateException(e); 298 } catch (IOException impossible) { 299 throw new AssertionError(impossible); 300 } 301 } 302 303 @Override public int readUnsignedByte() { 304 try { 305 return input.readUnsignedByte(); 306 } catch (IOException e) { 307 throw new IllegalStateException(e); 308 } 309 } 310 311 @Override public short readShort() { 312 try { 313 return input.readShort(); 314 } catch (IOException e) { 315 throw new IllegalStateException(e); 316 } 317 } 318 319 @Override public int readUnsignedShort() { 320 try { 321 return input.readUnsignedShort(); 322 } catch (IOException e) { 323 throw new IllegalStateException(e); 324 } 325 } 326 327 @Override public char readChar() { 328 try { 329 return input.readChar(); 330 } catch (IOException e) { 331 throw new IllegalStateException(e); 332 } 333 } 334 335 @Override public int readInt() { 336 try { 337 return input.readInt(); 338 } catch (IOException e) { 339 throw new IllegalStateException(e); 340 } 341 } 342 343 @Override public long readLong() { 344 try { 345 return input.readLong(); 346 } catch (IOException e) { 347 throw new IllegalStateException(e); 348 } 349 } 350 351 @Override public float readFloat() { 352 try { 353 return input.readFloat(); 354 } catch (IOException e) { 355 throw new IllegalStateException(e); 356 } 357 } 358 359 @Override public double readDouble() { 360 try { 361 return input.readDouble(); 362 } catch (IOException e) { 363 throw new IllegalStateException(e); 364 } 365 } 366 367 @Override public String readLine() { 368 try { 369 return input.readLine(); 370 } catch (IOException e) { 371 throw new IllegalStateException(e); 372 } 373 } 374 375 @Override public String readUTF() { 376 try { 377 return input.readUTF(); 378 } catch (IOException e) { 379 throw new IllegalStateException(e); 380 } 381 } 382 } 383 384 /** 385 * Returns a new {@link ByteArrayDataOutput} instance with a default size. 386 */ 387 public static ByteArrayDataOutput newDataOutput() { 388 return new ByteArrayDataOutputStream(); 389 } 390 391 /** 392 * Returns a new {@link ByteArrayDataOutput} instance sized to hold 393 * {@code size} bytes before resizing. 394 * 395 * @throws IllegalArgumentException if {@code size} is negative 396 */ 397 public static ByteArrayDataOutput newDataOutput(int size) { 398 checkArgument(size >= 0, "Invalid size: %s", size); 399 return new ByteArrayDataOutputStream(size); 400 } 401 402 @SuppressWarnings("deprecation") // for writeBytes 403 private static class ByteArrayDataOutputStream 404 implements ByteArrayDataOutput { 405 406 final DataOutput output; 407 final ByteArrayOutputStream byteArrayOutputSteam; 408 409 ByteArrayDataOutputStream() { 410 this(new ByteArrayOutputStream()); 411 } 412 413 ByteArrayDataOutputStream(int size) { 414 this(new ByteArrayOutputStream(size)); 415 } 416 417 ByteArrayDataOutputStream(ByteArrayOutputStream byteArrayOutputSteam) { 418 this.byteArrayOutputSteam = byteArrayOutputSteam; 419 output = new DataOutputStream(byteArrayOutputSteam); 420 } 421 422 @Override public void write(int b) { 423 try { 424 output.write(b); 425 } catch (IOException impossible) { 426 throw new AssertionError(impossible); 427 } 428 } 429 430 @Override public void write(byte[] b) { 431 try { 432 output.write(b); 433 } catch (IOException impossible) { 434 throw new AssertionError(impossible); 435 } 436 } 437 438 @Override public void write(byte[] b, int off, int len) { 439 try { 440 output.write(b, off, len); 441 } catch (IOException impossible) { 442 throw new AssertionError(impossible); 443 } 444 } 445 446 @Override public void writeBoolean(boolean v) { 447 try { 448 output.writeBoolean(v); 449 } catch (IOException impossible) { 450 throw new AssertionError(impossible); 451 } 452 } 453 454 @Override public void writeByte(int v) { 455 try { 456 output.writeByte(v); 457 } catch (IOException impossible) { 458 throw new AssertionError(impossible); 459 } 460 } 461 462 @Override public void writeBytes(String s) { 463 try { 464 output.writeBytes(s); 465 } catch (IOException impossible) { 466 throw new AssertionError(impossible); 467 } 468 } 469 470 @Override public void writeChar(int v) { 471 try { 472 output.writeChar(v); 473 } catch (IOException impossible) { 474 throw new AssertionError(impossible); 475 } 476 } 477 478 @Override public void writeChars(String s) { 479 try { 480 output.writeChars(s); 481 } catch (IOException impossible) { 482 throw new AssertionError(impossible); 483 } 484 } 485 486 @Override public void writeDouble(double v) { 487 try { 488 output.writeDouble(v); 489 } catch (IOException impossible) { 490 throw new AssertionError(impossible); 491 } 492 } 493 494 @Override public void writeFloat(float v) { 495 try { 496 output.writeFloat(v); 497 } catch (IOException impossible) { 498 throw new AssertionError(impossible); 499 } 500 } 501 502 @Override public void writeInt(int v) { 503 try { 504 output.writeInt(v); 505 } catch (IOException impossible) { 506 throw new AssertionError(impossible); 507 } 508 } 509 510 @Override public void writeLong(long v) { 511 try { 512 output.writeLong(v); 513 } catch (IOException impossible) { 514 throw new AssertionError(impossible); 515 } 516 } 517 518 @Override public void writeShort(int v) { 519 try { 520 output.writeShort(v); 521 } catch (IOException impossible) { 522 throw new AssertionError(impossible); 523 } 524 } 525 526 @Override public void writeUTF(String s) { 527 try { 528 output.writeUTF(s); 529 } catch (IOException impossible) { 530 throw new AssertionError(impossible); 531 } 532 } 533 534 @Override public byte[] toByteArray() { 535 return byteArrayOutputSteam.toByteArray(); 536 } 537 } 538 539 private static final OutputStream NULL_OUTPUT_STREAM = 540 new OutputStream() { 541 /** Discards the specified byte. */ 542 @Override public void write(int b) { 543 } 544 /** Discards the specified byte array. */ 545 @Override public void write(byte[] b) { 546 checkNotNull(b); 547 } 548 /** Discards the specified byte array. */ 549 @Override public void write(byte[] b, int off, int len) { 550 checkNotNull(b); 551 } 552 553 @Override 554 public String toString() { 555 return "ByteStreams.nullOutputStream()"; 556 } 557 }; 558 559 /** 560 * Returns an {@link OutputStream} that simply discards written bytes. 561 * 562 * @since 14.0 (since 1.0 as com.google.common.io.NullOutputStream) 563 */ 564 public static OutputStream nullOutputStream() { 565 return NULL_OUTPUT_STREAM; 566 } 567 568 /** 569 * Wraps a {@link InputStream}, limiting the number of bytes which can be 570 * read. 571 * 572 * @param in the input stream to be wrapped 573 * @param limit the maximum number of bytes to be read 574 * @return a length-limited {@link InputStream} 575 * @since 14.0 (since 1.0 as com.google.common.io.LimitInputStream) 576 */ 577 public static InputStream limit(InputStream in, long limit) { 578 return new LimitedInputStream(in, limit); 579 } 580 581 private static final class LimitedInputStream extends FilterInputStream { 582 583 private long left; 584 private long mark = -1; 585 586 LimitedInputStream(InputStream in, long limit) { 587 super(in); 588 checkNotNull(in); 589 checkArgument(limit >= 0, "limit must be non-negative"); 590 left = limit; 591 } 592 593 @Override public int available() throws IOException { 594 return (int) Math.min(in.available(), left); 595 } 596 597 // it's okay to mark even if mark isn't supported, as reset won't work 598 @Override public synchronized void mark(int readLimit) { 599 in.mark(readLimit); 600 mark = left; 601 } 602 603 @Override public int read() throws IOException { 604 if (left == 0) { 605 return -1; 606 } 607 608 int result = in.read(); 609 if (result != -1) { 610 --left; 611 } 612 return result; 613 } 614 615 @Override public int read(byte[] b, int off, int len) throws IOException { 616 if (left == 0) { 617 return -1; 618 } 619 620 len = (int) Math.min(len, left); 621 int result = in.read(b, off, len); 622 if (result != -1) { 623 left -= result; 624 } 625 return result; 626 } 627 628 @Override public synchronized void reset() throws IOException { 629 if (!in.markSupported()) { 630 throw new IOException("Mark not supported"); 631 } 632 if (mark == -1) { 633 throw new IOException("Mark not set"); 634 } 635 636 in.reset(); 637 left = mark; 638 } 639 640 @Override public long skip(long n) throws IOException { 641 n = Math.min(n, left); 642 long skipped = in.skip(n); 643 left -= skipped; 644 return skipped; 645 } 646 } 647 648 /** Returns the length of a supplied input stream, in bytes. */ 649 public static long length( 650 InputSupplier<? extends InputStream> supplier) throws IOException { 651 return asByteSource(supplier).size(); 652 } 653 654 /** 655 * Returns true if the supplied input streams contain the same bytes. 656 * 657 * @throws IOException if an I/O error occurs 658 */ 659 public static boolean equal(InputSupplier<? extends InputStream> supplier1, 660 InputSupplier<? extends InputStream> supplier2) throws IOException { 661 return asByteSource(supplier1).contentEquals(asByteSource(supplier2)); 662 } 663 664 /** 665 * Attempts to read enough bytes from the stream to fill the given byte array, 666 * with the same behavior as {@link DataInput#readFully(byte[])}. 667 * Does not close the stream. 668 * 669 * @param in the input stream to read from. 670 * @param b the buffer into which the data is read. 671 * @throws EOFException if this stream reaches the end before reading all 672 * the bytes. 673 * @throws IOException if an I/O error occurs. 674 */ 675 public static void readFully(InputStream in, byte[] b) throws IOException { 676 readFully(in, b, 0, b.length); 677 } 678 679 /** 680 * Attempts to read {@code len} bytes from the stream into the given array 681 * starting at {@code off}, with the same behavior as 682 * {@link DataInput#readFully(byte[], int, int)}. Does not close the 683 * stream. 684 * 685 * @param in the input stream to read from. 686 * @param b the buffer into which the data is read. 687 * @param off an int specifying the offset into the data. 688 * @param len an int specifying the number of bytes to read. 689 * @throws EOFException if this stream reaches the end before reading all 690 * the bytes. 691 * @throws IOException if an I/O error occurs. 692 */ 693 public static void readFully( 694 InputStream in, byte[] b, int off, int len) throws IOException { 695 int read = read(in, b, off, len); 696 if (read != len) { 697 throw new EOFException("reached end of stream after reading " 698 + read + " bytes; " + len + " bytes expected"); 699 } 700 } 701 702 /** 703 * Discards {@code n} bytes of data from the input stream. This method 704 * will block until the full amount has been skipped. Does not close the 705 * stream. 706 * 707 * @param in the input stream to read from 708 * @param n the number of bytes to skip 709 * @throws EOFException if this stream reaches the end before skipping all 710 * the bytes 711 * @throws IOException if an I/O error occurs, or the stream does not 712 * support skipping 713 */ 714 public static void skipFully(InputStream in, long n) throws IOException { 715 long toSkip = n; 716 while (n > 0) { 717 long amt = in.skip(n); 718 if (amt == 0) { 719 // Force a blocking read to avoid infinite loop 720 if (in.read() == -1) { 721 long skipped = toSkip - n; 722 throw new EOFException("reached end of stream after skipping " 723 + skipped + " bytes; " + toSkip + " bytes expected"); 724 } 725 n--; 726 } else { 727 n -= amt; 728 } 729 } 730 } 731 732 /** 733 * Process the bytes of a supplied stream 734 * 735 * @param supplier the input stream factory 736 * @param processor the object to which to pass the bytes of the stream 737 * @return the result of the byte processor 738 * @throws IOException if an I/O error occurs 739 */ 740 public static <T> T readBytes( 741 InputSupplier<? extends InputStream> supplier, 742 ByteProcessor<T> processor) throws IOException { 743 checkNotNull(supplier); 744 checkNotNull(processor); 745 746 Closer closer = Closer.create(); 747 try { 748 InputStream in = closer.register(supplier.getInput()); 749 return readBytes(in, processor); 750 } catch (Throwable e) { 751 throw closer.rethrow(e); 752 } finally { 753 closer.close(); 754 } 755 } 756 757 /** 758 * Process the bytes of the given input stream using the given processor. 759 * 760 * @param input the input stream to process 761 * @param processor the object to which to pass the bytes of the stream 762 * @return the result of the byte processor 763 * @throws IOException if an I/O error occurs 764 * @since 14.0 765 */ 766 public static <T> T readBytes( 767 InputStream input, ByteProcessor<T> processor) throws IOException { 768 checkNotNull(input); 769 checkNotNull(processor); 770 771 byte[] buf = new byte[BUF_SIZE]; 772 int read; 773 do { 774 read = input.read(buf); 775 } while (read != -1 && processor.processBytes(buf, 0, read)); 776 return processor.getResult(); 777 } 778 779 /** 780 * Computes the hash code of the data supplied by {@code supplier} using {@code 781 * hashFunction}. 782 * 783 * @param supplier the input stream factory 784 * @param hashFunction the hash function to use to hash the data 785 * @return the {@link HashCode} of all of the bytes in the input stream 786 * @throws IOException if an I/O error occurs 787 * @since 12.0 788 */ 789 public static HashCode hash( 790 InputSupplier<? extends InputStream> supplier, HashFunction hashFunction) 791 throws IOException { 792 return asByteSource(supplier).hash(hashFunction); 793 } 794 795 /** 796 * Reads some bytes from an input stream and stores them into the buffer array 797 * {@code b}. This method blocks until {@code len} bytes of input data have 798 * been read into the array, or end of file is detected. The number of bytes 799 * read is returned, possibly zero. Does not close the stream. 800 * 801 * <p>A caller can detect EOF if the number of bytes read is less than 802 * {@code len}. All subsequent calls on the same stream will return zero. 803 * 804 * <p>If {@code b} is null, a {@code NullPointerException} is thrown. If 805 * {@code off} is negative, or {@code len} is negative, or {@code off+len} is 806 * greater than the length of the array {@code b}, then an 807 * {@code IndexOutOfBoundsException} is thrown. If {@code len} is zero, then 808 * no bytes are read. Otherwise, the first byte read is stored into element 809 * {@code b[off]}, the next one into {@code b[off+1]}, and so on. The number 810 * of bytes read is, at most, equal to {@code len}. 811 * 812 * @param in the input stream to read from 813 * @param b the buffer into which the data is read 814 * @param off an int specifying the offset into the data 815 * @param len an int specifying the number of bytes to read 816 * @return the number of bytes read 817 * @throws IOException if an I/O error occurs 818 */ 819 public static int read(InputStream in, byte[] b, int off, int len) 820 throws IOException { 821 checkNotNull(in); 822 checkNotNull(b); 823 if (len < 0) { 824 throw new IndexOutOfBoundsException("len is negative"); 825 } 826 int total = 0; 827 while (total < len) { 828 int result = in.read(b, off + total, len - total); 829 if (result == -1) { 830 break; 831 } 832 total += result; 833 } 834 return total; 835 } 836 837 /** 838 * Returns an {@link InputSupplier} that returns input streams from the 839 * an underlying supplier, where each stream starts at the given 840 * offset and is limited to the specified number of bytes. 841 * 842 * @param supplier the supplier from which to get the raw streams 843 * @param offset the offset in bytes into the underlying stream where 844 * the returned streams will start 845 * @param length the maximum length of the returned streams 846 * @throws IllegalArgumentException if offset or length are negative 847 */ 848 public static InputSupplier<InputStream> slice( 849 final InputSupplier<? extends InputStream> supplier, 850 final long offset, 851 final long length) { 852 return asInputSupplier(asByteSource(supplier).slice(offset, length)); 853 } 854 855 /** 856 * Joins multiple {@link InputStream} suppliers into a single supplier. 857 * Streams returned from the supplier will contain the concatenated data from 858 * the streams of the underlying suppliers. 859 * 860 * <p>Only one underlying input stream will be open at a time. Closing the 861 * joined stream will close the open underlying stream. 862 * 863 * <p>Reading from the joined stream will throw a {@link NullPointerException} 864 * if any of the suppliers are null or return null. 865 * 866 * @param suppliers the suppliers to concatenate 867 * @return a supplier that will return a stream containing the concatenated 868 * stream data 869 */ 870 public static InputSupplier<InputStream> join( 871 final Iterable<? extends InputSupplier<? extends InputStream>> suppliers) { 872 checkNotNull(suppliers); 873 Iterable<ByteSource> sources = Iterables.transform(suppliers, 874 new Function<InputSupplier<? extends InputStream>, ByteSource>() { 875 @Override 876 public ByteSource apply(InputSupplier<? extends InputStream> input) { 877 return asByteSource(input); 878 } 879 }); 880 return asInputSupplier(ByteSource.concat(sources)); 881 } 882 883 /** Varargs form of {@link #join(Iterable)}. */ 884 @SuppressWarnings("unchecked") // suppress "possible heap pollution" warning in JDK7 885 public static InputSupplier<InputStream> join( 886 InputSupplier<? extends InputStream>... suppliers) { 887 return join(Arrays.asList(suppliers)); 888 } 889 890 // TODO(user): Remove these once Input/OutputSupplier methods are removed 891 892 /** 893 * Returns a view of the given {@code InputStream} supplier as a 894 * {@code ByteSource}. 895 * 896 * <p>This method is a temporary method provided for easing migration from 897 * suppliers to sources and sinks. 898 * 899 * @since 15.0 900 */ 901 public static ByteSource asByteSource( 902 final InputSupplier<? extends InputStream> supplier) { 903 checkNotNull(supplier); 904 return new ByteSource() { 905 @Override 906 public InputStream openStream() throws IOException { 907 return supplier.getInput(); 908 } 909 910 @Override 911 public String toString() { 912 return "ByteStreams.asByteSource(" + supplier + ")"; 913 } 914 }; 915 } 916 917 /** 918 * Returns a view of the given {@code OutputStream} supplier as a 919 * {@code ByteSink}. 920 * 921 * <p>This method is a temporary method provided for easing migration from 922 * suppliers to sources and sinks. 923 * 924 * @since 15.0 925 */ 926 public static ByteSink asByteSink( 927 final OutputSupplier<? extends OutputStream> supplier) { 928 checkNotNull(supplier); 929 return new ByteSink() { 930 @Override 931 public OutputStream openStream() throws IOException { 932 return supplier.getOutput(); 933 } 934 935 @Override 936 public String toString() { 937 return "ByteStreams.asByteSink(" + supplier + ")"; 938 } 939 }; 940 } 941 942 @SuppressWarnings("unchecked") // used internally where known to be safe 943 static <S extends InputStream> InputSupplier<S> asInputSupplier( 944 final ByteSource source) { 945 return (InputSupplier) checkNotNull(source); 946 } 947 948 @SuppressWarnings("unchecked") // used internally where known to be safe 949 static <S extends OutputStream> OutputSupplier<S> asOutputSupplier( 950 final ByteSink sink) { 951 return (OutputSupplier) checkNotNull(sink); 952 } 953}