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; 024 025import java.io.ByteArrayInputStream; 026import java.io.ByteArrayOutputStream; 027import java.io.DataInput; 028import java.io.DataInputStream; 029import java.io.DataOutput; 030import java.io.DataOutputStream; 031import java.io.EOFException; 032import java.io.FilterInputStream; 033import java.io.IOException; 034import java.io.InputStream; 035import java.io.OutputStream; 036import java.nio.ByteBuffer; 037import java.nio.channels.FileChannel; 038import java.nio.channels.ReadableByteChannel; 039import java.nio.channels.WritableByteChannel; 040import java.util.Arrays; 041 042/** 043 * Provides utility methods for working with byte arrays and I/O streams. 044 * 045 * @author Chris Nokleberg 046 * @author Colin Decker 047 * @since 1.0 048 */ 049@Beta 050public final class ByteStreams { 051 052 /** 053 * Default size of buffers allocated for copies. 054 */ 055 static final int BUF_SIZE = 8192; 056 057 /** 058 * A buffer for skipping bytes in an input stream. Only written to and never read, so actual 059 * contents don't matter. 060 */ 061 static final byte[] skipBuffer = new byte[BUF_SIZE]; 062 063 /** 064 * There are three methods to implement {@link FileChannel#transferTo(long, long, 065 * WritableByteChannel)}: 066 * 067 * <ol> 068 * <li> Use sendfile(2) or equivalent. Requires that both the input channel and the output channel 069 * have their own file descriptors. Generally this only happens when both channels are files or 070 * sockets. This performs zero copies - the bytes never enter userspace.</li> 071 * <li> Use mmap(2) or equivalent. Requires that either the input channel or the output channel 072 * have file descriptors. Bytes are copied from the file into a kernel buffer, then directly 073 * into the other buffer (userspace). Note that if the file is very large, a naive 074 * implementation will effectively put the whole file in memory. On many systems with paging 075 * and virtual memory, this is not a problem - because it is mapped read-only, the kernel can 076 * always page it to disk "for free". However, on systems where killing processes happens all 077 * the time in normal conditions (i.e., android) the OS must make a tradeoff between paging 078 * memory and killing other processes - so allocating a gigantic buffer and then sequentially 079 * accessing it could result in other processes dying. This is solvable via madvise(2), but 080 * that obviously doesn't exist in java.</li> 081 * <li> Ordinary copy. Kernel copies bytes into a kernel buffer, from a kernel buffer into a 082 * userspace buffer (byte[] or ByteBuffer), then copies them from that buffer into the 083 * destination channel.</li> 084 * </ol> 085 * 086 * This value is intended to be large enough to make the overhead of system calls negligible, 087 * without being so large that it causes problems for systems with atypical memory management if 088 * approaches 2 or 3 are used. 089 */ 090 private static final int ZERO_COPY_CHUNK_SIZE = 512 * 1024; 091 092 private ByteStreams() {} 093 094 /** 095 * Copies all bytes from the input stream to the output stream. 096 * Does not close or flush either stream. 097 * 098 * @param from the input stream to read from 099 * @param to the output stream to write to 100 * @return the number of bytes copied 101 * @throws IOException if an I/O error occurs 102 */ 103 public static long copy(InputStream from, OutputStream to) 104 throws IOException { 105 checkNotNull(from); 106 checkNotNull(to); 107 byte[] buf = new byte[BUF_SIZE]; 108 long total = 0; 109 while (true) { 110 int r = from.read(buf); 111 if (r == -1) { 112 break; 113 } 114 to.write(buf, 0, r); 115 total += r; 116 } 117 return total; 118 } 119 120 /** 121 * Copies all bytes from the readable channel to the writable channel. 122 * Does not close or flush either channel. 123 * 124 * @param from the readable channel to read from 125 * @param to the writable channel to write to 126 * @return the number of bytes copied 127 * @throws IOException if an I/O error occurs 128 */ 129 public static long copy(ReadableByteChannel from, 130 WritableByteChannel to) throws IOException { 131 checkNotNull(from); 132 checkNotNull(to); 133 if (from instanceof FileChannel) { 134 FileChannel sourceChannel = (FileChannel) from; 135 long oldPosition = sourceChannel.position(); 136 long position = oldPosition; 137 long copied; 138 do { 139 copied = sourceChannel.transferTo(position, ZERO_COPY_CHUNK_SIZE, to); 140 position += copied; 141 sourceChannel.position(position); 142 } while (copied > 0 || position < sourceChannel.size()); 143 return position - oldPosition; 144 } 145 146 ByteBuffer buf = ByteBuffer.allocate(BUF_SIZE); 147 long total = 0; 148 while (from.read(buf) != -1) { 149 buf.flip(); 150 while (buf.hasRemaining()) { 151 total += to.write(buf); 152 } 153 buf.clear(); 154 } 155 return total; 156 } 157 158 /** 159 * Reads all bytes from an input stream into a byte array. 160 * Does not close the stream. 161 * 162 * @param in the input stream to read from 163 * @return a byte array containing all the bytes from the stream 164 * @throws IOException if an I/O error occurs 165 */ 166 public static byte[] toByteArray(InputStream in) throws IOException { 167 ByteArrayOutputStream out = new ByteArrayOutputStream(); 168 copy(in, out); 169 return out.toByteArray(); 170 } 171 172 /** 173 * Reads all bytes from an input stream into a byte array. The given 174 * expected size is used to create an initial byte array, but if the actual 175 * number of bytes read from the stream differs, the correct result will be 176 * returned anyway. 177 */ 178 static byte[] toByteArray( 179 InputStream in, int expectedSize) throws IOException { 180 byte[] bytes = new byte[expectedSize]; 181 int remaining = expectedSize; 182 183 while (remaining > 0) { 184 int off = expectedSize - remaining; 185 int read = in.read(bytes, off, remaining); 186 if (read == -1) { 187 // end of stream before reading expectedSize bytes 188 // just return the bytes read so far 189 return Arrays.copyOf(bytes, off); 190 } 191 remaining -= read; 192 } 193 194 // bytes is now full 195 int b = in.read(); 196 if (b == -1) { 197 return bytes; 198 } 199 200 // the stream was longer, so read the rest normally 201 FastByteArrayOutputStream out = new FastByteArrayOutputStream(); 202 out.write(b); // write the byte we read when testing for end of stream 203 copy(in, out); 204 205 byte[] result = new byte[bytes.length + out.size()]; 206 System.arraycopy(bytes, 0, result, 0, bytes.length); 207 out.writeTo(result, bytes.length); 208 return result; 209 } 210 211 /** 212 * BAOS that provides limited access to its internal byte array. 213 */ 214 private static final class FastByteArrayOutputStream 215 extends ByteArrayOutputStream { 216 /** 217 * Writes the contents of the internal buffer to the given array starting 218 * at the given offset. Assumes the array has space to hold count bytes. 219 */ 220 void writeTo(byte[] b, int off) { 221 System.arraycopy(buf, 0, b, off, count); 222 } 223 } 224 225 /** 226 * Returns a new {@link ByteArrayDataInput} instance to read from the {@code 227 * bytes} array from the beginning. 228 */ 229 public static ByteArrayDataInput newDataInput(byte[] bytes) { 230 return newDataInput(new ByteArrayInputStream(bytes)); 231 } 232 233 /** 234 * Returns a new {@link ByteArrayDataInput} instance to read from the {@code 235 * bytes} array, starting at the given position. 236 * 237 * @throws IndexOutOfBoundsException if {@code start} is negative or greater 238 * than the length of the array 239 */ 240 public static ByteArrayDataInput newDataInput(byte[] bytes, int start) { 241 checkPositionIndex(start, bytes.length); 242 return newDataInput( 243 new ByteArrayInputStream(bytes, start, bytes.length - start)); 244 } 245 246 /** 247 * Returns a new {@link ByteArrayDataInput} instance to read from the given 248 * {@code ByteArrayInputStream}. The given input stream is not reset before 249 * being read from by the returned {@code ByteArrayDataInput}. 250 * 251 * @since 17.0 252 */ 253 public static ByteArrayDataInput newDataInput( 254 ByteArrayInputStream byteArrayInputStream) { 255 return new ByteArrayDataInputStream(checkNotNull(byteArrayInputStream)); 256 } 257 258 private static class ByteArrayDataInputStream implements ByteArrayDataInput { 259 final DataInput input; 260 261 ByteArrayDataInputStream(ByteArrayInputStream byteArrayInputStream) { 262 this.input = new DataInputStream(byteArrayInputStream); 263 } 264 265 @Override public void readFully(byte b[]) { 266 try { 267 input.readFully(b); 268 } catch (IOException e) { 269 throw new IllegalStateException(e); 270 } 271 } 272 273 @Override public void readFully(byte b[], int off, int len) { 274 try { 275 input.readFully(b, off, len); 276 } catch (IOException e) { 277 throw new IllegalStateException(e); 278 } 279 } 280 281 @Override public int skipBytes(int n) { 282 try { 283 return input.skipBytes(n); 284 } catch (IOException e) { 285 throw new IllegalStateException(e); 286 } 287 } 288 289 @Override public boolean readBoolean() { 290 try { 291 return input.readBoolean(); 292 } catch (IOException e) { 293 throw new IllegalStateException(e); 294 } 295 } 296 297 @Override public byte readByte() { 298 try { 299 return input.readByte(); 300 } catch (EOFException e) { 301 throw new IllegalStateException(e); 302 } catch (IOException impossible) { 303 throw new AssertionError(impossible); 304 } 305 } 306 307 @Override public int readUnsignedByte() { 308 try { 309 return input.readUnsignedByte(); 310 } catch (IOException e) { 311 throw new IllegalStateException(e); 312 } 313 } 314 315 @Override public short readShort() { 316 try { 317 return input.readShort(); 318 } catch (IOException e) { 319 throw new IllegalStateException(e); 320 } 321 } 322 323 @Override public int readUnsignedShort() { 324 try { 325 return input.readUnsignedShort(); 326 } catch (IOException e) { 327 throw new IllegalStateException(e); 328 } 329 } 330 331 @Override public char readChar() { 332 try { 333 return input.readChar(); 334 } catch (IOException e) { 335 throw new IllegalStateException(e); 336 } 337 } 338 339 @Override public int readInt() { 340 try { 341 return input.readInt(); 342 } catch (IOException e) { 343 throw new IllegalStateException(e); 344 } 345 } 346 347 @Override public long readLong() { 348 try { 349 return input.readLong(); 350 } catch (IOException e) { 351 throw new IllegalStateException(e); 352 } 353 } 354 355 @Override public float readFloat() { 356 try { 357 return input.readFloat(); 358 } catch (IOException e) { 359 throw new IllegalStateException(e); 360 } 361 } 362 363 @Override public double readDouble() { 364 try { 365 return input.readDouble(); 366 } catch (IOException e) { 367 throw new IllegalStateException(e); 368 } 369 } 370 371 @Override public String readLine() { 372 try { 373 return input.readLine(); 374 } catch (IOException e) { 375 throw new IllegalStateException(e); 376 } 377 } 378 379 @Override public String readUTF() { 380 try { 381 return input.readUTF(); 382 } catch (IOException e) { 383 throw new IllegalStateException(e); 384 } 385 } 386 } 387 388 /** 389 * Returns a new {@link ByteArrayDataOutput} instance with a default size. 390 */ 391 public static ByteArrayDataOutput newDataOutput() { 392 return newDataOutput(new ByteArrayOutputStream()); 393 } 394 395 /** 396 * Returns a new {@link ByteArrayDataOutput} instance sized to hold 397 * {@code size} bytes before resizing. 398 * 399 * @throws IllegalArgumentException if {@code size} is negative 400 */ 401 public static ByteArrayDataOutput newDataOutput(int size) { 402 // When called at high frequency, boxing size generates too much garbage, 403 // so avoid doing that if we can. 404 if (size < 0) { 405 throw new IllegalArgumentException(String.format("Invalid size: %s", size)); 406 } 407 return newDataOutput(new ByteArrayOutputStream(size)); 408 } 409 410 /** 411 * Returns a new {@link ByteArrayDataOutput} instance which writes to the 412 * given {@code ByteArrayOutputStream}. The given output stream is not reset 413 * before being written to by the returned {@code ByteArrayDataOutput} and 414 * new data will be appended to any existing content. 415 * 416 * <p>Note that if the given output stream was not empty or is modified after 417 * the {@code ByteArrayDataOutput} is created, the contract for 418 * {@link ByteArrayDataOutput#toByteArray} will not be honored (the bytes 419 * returned in the byte array may not be exactly what was written via calls to 420 * {@code ByteArrayDataOutput}). 421 * 422 * @since 17.0 423 */ 424 public static ByteArrayDataOutput newDataOutput( 425 ByteArrayOutputStream byteArrayOutputSteam) { 426 return new ByteArrayDataOutputStream(checkNotNull(byteArrayOutputSteam)); 427 } 428 429 @SuppressWarnings("deprecation") // for writeBytes 430 private static class ByteArrayDataOutputStream 431 implements ByteArrayDataOutput { 432 433 final DataOutput output; 434 final ByteArrayOutputStream byteArrayOutputSteam; 435 436 ByteArrayDataOutputStream(ByteArrayOutputStream byteArrayOutputSteam) { 437 this.byteArrayOutputSteam = byteArrayOutputSteam; 438 output = new DataOutputStream(byteArrayOutputSteam); 439 } 440 441 @Override public void write(int b) { 442 try { 443 output.write(b); 444 } catch (IOException impossible) { 445 throw new AssertionError(impossible); 446 } 447 } 448 449 @Override public void write(byte[] b) { 450 try { 451 output.write(b); 452 } catch (IOException impossible) { 453 throw new AssertionError(impossible); 454 } 455 } 456 457 @Override public void write(byte[] b, int off, int len) { 458 try { 459 output.write(b, off, len); 460 } catch (IOException impossible) { 461 throw new AssertionError(impossible); 462 } 463 } 464 465 @Override public void writeBoolean(boolean v) { 466 try { 467 output.writeBoolean(v); 468 } catch (IOException impossible) { 469 throw new AssertionError(impossible); 470 } 471 } 472 473 @Override public void writeByte(int v) { 474 try { 475 output.writeByte(v); 476 } catch (IOException impossible) { 477 throw new AssertionError(impossible); 478 } 479 } 480 481 @Override public void writeBytes(String s) { 482 try { 483 output.writeBytes(s); 484 } catch (IOException impossible) { 485 throw new AssertionError(impossible); 486 } 487 } 488 489 @Override public void writeChar(int v) { 490 try { 491 output.writeChar(v); 492 } catch (IOException impossible) { 493 throw new AssertionError(impossible); 494 } 495 } 496 497 @Override public void writeChars(String s) { 498 try { 499 output.writeChars(s); 500 } catch (IOException impossible) { 501 throw new AssertionError(impossible); 502 } 503 } 504 505 @Override public void writeDouble(double v) { 506 try { 507 output.writeDouble(v); 508 } catch (IOException impossible) { 509 throw new AssertionError(impossible); 510 } 511 } 512 513 @Override public void writeFloat(float v) { 514 try { 515 output.writeFloat(v); 516 } catch (IOException impossible) { 517 throw new AssertionError(impossible); 518 } 519 } 520 521 @Override public void writeInt(int v) { 522 try { 523 output.writeInt(v); 524 } catch (IOException impossible) { 525 throw new AssertionError(impossible); 526 } 527 } 528 529 @Override public void writeLong(long v) { 530 try { 531 output.writeLong(v); 532 } catch (IOException impossible) { 533 throw new AssertionError(impossible); 534 } 535 } 536 537 @Override public void writeShort(int v) { 538 try { 539 output.writeShort(v); 540 } catch (IOException impossible) { 541 throw new AssertionError(impossible); 542 } 543 } 544 545 @Override public void writeUTF(String s) { 546 try { 547 output.writeUTF(s); 548 } catch (IOException impossible) { 549 throw new AssertionError(impossible); 550 } 551 } 552 553 @Override public byte[] toByteArray() { 554 return byteArrayOutputSteam.toByteArray(); 555 } 556 } 557 558 private static final OutputStream NULL_OUTPUT_STREAM = 559 new OutputStream() { 560 /** Discards the specified byte. */ 561 @Override public void write(int b) { 562 } 563 /** Discards the specified byte array. */ 564 @Override public void write(byte[] b) { 565 checkNotNull(b); 566 } 567 /** Discards the specified byte array. */ 568 @Override public void write(byte[] b, int off, int len) { 569 checkNotNull(b); 570 } 571 572 @Override 573 public String toString() { 574 return "ByteStreams.nullOutputStream()"; 575 } 576 }; 577 578 /** 579 * Returns an {@link OutputStream} that simply discards written bytes. 580 * 581 * @since 14.0 (since 1.0 as com.google.common.io.NullOutputStream) 582 */ 583 public static OutputStream nullOutputStream() { 584 return NULL_OUTPUT_STREAM; 585 } 586 587 /** 588 * Wraps a {@link InputStream}, limiting the number of bytes which can be 589 * read. 590 * 591 * @param in the input stream to be wrapped 592 * @param limit the maximum number of bytes to be read 593 * @return a length-limited {@link InputStream} 594 * @since 14.0 (since 1.0 as com.google.common.io.LimitInputStream) 595 */ 596 public static InputStream limit(InputStream in, long limit) { 597 return new LimitedInputStream(in, limit); 598 } 599 600 private static final class LimitedInputStream extends FilterInputStream { 601 602 private long left; 603 private long mark = -1; 604 605 LimitedInputStream(InputStream in, long limit) { 606 super(in); 607 checkNotNull(in); 608 checkArgument(limit >= 0, "limit must be non-negative"); 609 left = limit; 610 } 611 612 @Override public int available() throws IOException { 613 return (int) Math.min(in.available(), left); 614 } 615 616 // it's okay to mark even if mark isn't supported, as reset won't work 617 @Override public synchronized void mark(int readLimit) { 618 in.mark(readLimit); 619 mark = left; 620 } 621 622 @Override public int read() throws IOException { 623 if (left == 0) { 624 return -1; 625 } 626 627 int result = in.read(); 628 if (result != -1) { 629 --left; 630 } 631 return result; 632 } 633 634 @Override public int read(byte[] b, int off, int len) throws IOException { 635 if (left == 0) { 636 return -1; 637 } 638 639 len = (int) Math.min(len, left); 640 int result = in.read(b, off, len); 641 if (result != -1) { 642 left -= result; 643 } 644 return result; 645 } 646 647 @Override public synchronized void reset() throws IOException { 648 if (!in.markSupported()) { 649 throw new IOException("Mark not supported"); 650 } 651 if (mark == -1) { 652 throw new IOException("Mark not set"); 653 } 654 655 in.reset(); 656 left = mark; 657 } 658 659 @Override public long skip(long n) throws IOException { 660 n = Math.min(n, left); 661 long skipped = in.skip(n); 662 left -= skipped; 663 return skipped; 664 } 665 } 666 667 /** 668 * Attempts to read enough bytes from the stream to fill the given byte array, 669 * with the same behavior as {@link DataInput#readFully(byte[])}. 670 * Does not close the stream. 671 * 672 * @param in the input stream to read from. 673 * @param b the buffer into which the data is read. 674 * @throws EOFException if this stream reaches the end before reading all 675 * the bytes. 676 * @throws IOException if an I/O error occurs. 677 */ 678 public static void readFully(InputStream in, byte[] b) throws IOException { 679 readFully(in, b, 0, b.length); 680 } 681 682 /** 683 * Attempts to read {@code len} bytes from the stream into the given array 684 * starting at {@code off}, with the same behavior as 685 * {@link DataInput#readFully(byte[], int, int)}. Does not close the 686 * stream. 687 * 688 * @param in the input stream to read from. 689 * @param b the buffer into which the data is read. 690 * @param off an int specifying the offset into the data. 691 * @param len an int specifying the number of bytes to read. 692 * @throws EOFException if this stream reaches the end before reading all 693 * the bytes. 694 * @throws IOException if an I/O error occurs. 695 */ 696 public static void readFully( 697 InputStream in, byte[] b, int off, int len) throws IOException { 698 int read = read(in, b, off, len); 699 if (read != len) { 700 throw new EOFException("reached end of stream after reading " 701 + read + " bytes; " + len + " bytes expected"); 702 } 703 } 704 705 /** 706 * Discards {@code n} bytes of data from the input stream. This method 707 * will block until the full amount has been skipped. Does not close the 708 * stream. 709 * 710 * @param in the input stream to read from 711 * @param n the number of bytes to skip 712 * @throws EOFException if this stream reaches the end before skipping all 713 * the bytes 714 * @throws IOException if an I/O error occurs, or the stream does not 715 * support skipping 716 */ 717 public static void skipFully(InputStream in, long n) throws IOException { 718 long skipped = skipUpTo(in, n); 719 if (skipped < n) { 720 throw new EOFException("reached end of stream after skipping " 721 + skipped + " bytes; " + n + " bytes expected"); 722 } 723 } 724 725 /** 726 * Discards up to {@code n} bytes of data from the input stream. This method 727 * will block until either the full amount has been skipped or until the end 728 * of the stream is reached, whichever happens first. Returns the total number 729 * of bytes skipped. 730 */ 731 static long skipUpTo(InputStream in, final long n) throws IOException { 732 long totalSkipped = 0; 733 734 while (totalSkipped < n) { 735 long remaining = n - totalSkipped; 736 737 long skipped = skipSafely(in, remaining); 738 739 if (skipped == 0) { 740 // Do a buffered read since skipSafely could return 0 repeatedly, for example if 741 // in.available() always returns 0 (the default). 742 int skip = (int) Math.min(remaining, skipBuffer.length); 743 if ((skipped = in.read(skipBuffer, 0, skip)) == -1) { 744 // Reached EOF 745 break; 746 } 747 } 748 749 totalSkipped += skipped; 750 } 751 752 return totalSkipped; 753 } 754 755 /** 756 * Attempts to skip up to {@code n} bytes from the given input stream, but not more than 757 * {@code in.available()} bytes. This prevents {@code FileInputStream} from skipping more bytes 758 * than actually remain in the file, something that it 759 * {@linkplain FileInputStream#skip(long) specifies} it can do in its Javadoc despite the fact 760 * that it is violating the contract of {@code InputStream.skip()}. 761 */ 762 private static long skipSafely(InputStream in, long n) throws IOException { 763 int available = in.available(); 764 return available == 0 ? 0 : in.skip(Math.min(available, n)); 765 } 766 767 /** 768 * Process the bytes of the given input stream using the given processor. 769 * 770 * @param input the input stream to process 771 * @param processor the object to which to pass the bytes of the stream 772 * @return the result of the byte processor 773 * @throws IOException if an I/O error occurs 774 * @since 14.0 775 */ 776 public static <T> T readBytes( 777 InputStream input, ByteProcessor<T> processor) throws IOException { 778 checkNotNull(input); 779 checkNotNull(processor); 780 781 byte[] buf = new byte[BUF_SIZE]; 782 int read; 783 do { 784 read = input.read(buf); 785 } while (read != -1 && processor.processBytes(buf, 0, read)); 786 return processor.getResult(); 787 } 788 789 /** 790 * Reads some bytes from an input stream and stores them into the buffer array 791 * {@code b}. This method blocks until {@code len} bytes of input data have 792 * been read into the array, or end of file is detected. The number of bytes 793 * read is returned, possibly zero. Does not close the stream. 794 * 795 * <p>A caller can detect EOF if the number of bytes read is less than 796 * {@code len}. All subsequent calls on the same stream will return zero. 797 * 798 * <p>If {@code b} is null, a {@code NullPointerException} is thrown. If 799 * {@code off} is negative, or {@code len} is negative, or {@code off+len} is 800 * greater than the length of the array {@code b}, then an 801 * {@code IndexOutOfBoundsException} is thrown. If {@code len} is zero, then 802 * no bytes are read. Otherwise, the first byte read is stored into element 803 * {@code b[off]}, the next one into {@code b[off+1]}, and so on. The number 804 * of bytes read is, at most, equal to {@code len}. 805 * 806 * @param in the input stream to read from 807 * @param b the buffer into which the data is read 808 * @param off an int specifying the offset into the data 809 * @param len an int specifying the number of bytes to read 810 * @return the number of bytes read 811 * @throws IOException if an I/O error occurs 812 */ 813 public static int read(InputStream in, byte[] b, int off, int len) 814 throws IOException { 815 checkNotNull(in); 816 checkNotNull(b); 817 if (len < 0) { 818 throw new IndexOutOfBoundsException("len is negative"); 819 } 820 int total = 0; 821 while (total < len) { 822 int result = in.read(b, off + total, len - total); 823 if (result == -1) { 824 break; 825 } 826 total += result; 827 } 828 return total; 829 } 830}