Coverage Summary for Class: ByteStreams (com.google.common.io)

Class Method, % Line, %
ByteStreams 0% (0/25) 0% (0/138)
ByteStreams$1 0% (0/4) 0% (0/4)
ByteStreams$ByteArrayDataInputStream 0% (0/16) 0% (0/51)
ByteStreams$ByteArrayDataOutputStream 0% (0/16) 0% (0/60)
ByteStreams$LimitedInputStream 0% (0/7) 0% (0/31)
Total 0% (0/68) 0% (0/284)


1 /* 2  * Copyright (C) 2007 The Guava Authors 3  * 4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5  * in compliance with the License. You may obtain a copy of the License at 6  * 7  * http://www.apache.org/licenses/LICENSE-2.0 8  * 9  * Unless required by applicable law or agreed to in writing, software distributed under the License 10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11  * or implied. See the License for the specific language governing permissions and limitations under 12  * the License. 13  */ 14  15 package com.google.common.io; 16  17 import static com.google.common.base.Preconditions.checkArgument; 18 import static com.google.common.base.Preconditions.checkNotNull; 19 import static com.google.common.base.Preconditions.checkPositionIndex; 20 import static com.google.common.base.Preconditions.checkPositionIndexes; 21  22 import com.google.common.annotations.Beta; 23 import com.google.common.annotations.GwtIncompatible; 24 import com.google.common.math.IntMath; 25 import com.google.errorprone.annotations.CanIgnoreReturnValue; 26 import java.io.ByteArrayInputStream; 27 import java.io.ByteArrayOutputStream; 28 import java.io.DataInput; 29 import java.io.DataInputStream; 30 import java.io.DataOutput; 31 import java.io.DataOutputStream; 32 import java.io.EOFException; 33 import java.io.FilterInputStream; 34 import java.io.IOException; 35 import java.io.InputStream; 36 import java.io.OutputStream; 37 import java.nio.ByteBuffer; 38 import java.nio.channels.FileChannel; 39 import java.nio.channels.ReadableByteChannel; 40 import java.nio.channels.WritableByteChannel; 41 import java.util.ArrayDeque; 42 import java.util.Arrays; 43 import java.util.Queue; 44 import javax.annotation.CheckForNull; 45 import org.checkerframework.checker.nullness.qual.Nullable; 46  47 /** 48  * Provides utility methods for working with byte arrays and I/O streams. 49  * 50  * @author Chris Nokleberg 51  * @author Colin Decker 52  * @since 1.0 53  */ 54 @GwtIncompatible 55 @ElementTypesAreNonnullByDefault 56 public final class ByteStreams { 57  58  private static final int BUFFER_SIZE = 8192; 59  60  /** Creates a new byte array for buffering reads or writes. */ 61  static byte[] createBuffer() { 62  return new byte[BUFFER_SIZE]; 63  } 64  65  /** 66  * There are three methods to implement {@link FileChannel#transferTo(long, long, 67  * WritableByteChannel)}: 68  * 69  * <ol> 70  * <li>Use sendfile(2) or equivalent. Requires that both the input channel and the output 71  * channel have their own file descriptors. Generally this only happens when both channels 72  * are files or sockets. This performs zero copies - the bytes never enter userspace. 73  * <li>Use mmap(2) or equivalent. Requires that either the input channel or the output channel 74  * have file descriptors. Bytes are copied from the file into a kernel buffer, then directly 75  * into the other buffer (userspace). Note that if the file is very large, a naive 76  * implementation will effectively put the whole file in memory. On many systems with paging 77  * and virtual memory, this is not a problem - because it is mapped read-only, the kernel 78  * can always page it to disk "for free". However, on systems where killing processes 79  * happens all the time in normal conditions (i.e., android) the OS must make a tradeoff 80  * between paging memory and killing other processes - so allocating a gigantic buffer and 81  * then sequentially accessing it could result in other processes dying. This is solvable 82  * via madvise(2), but that obviously doesn't exist in java. 83  * <li>Ordinary copy. Kernel copies bytes into a kernel buffer, from a kernel buffer into a 84  * userspace buffer (byte[] or ByteBuffer), then copies them from that buffer into the 85  * destination channel. 86  * </ol> 87  * 88  * This value is intended to be large enough to make the overhead of system calls negligible, 89  * without being so large that it causes problems for systems with atypical memory management if 90  * approaches 2 or 3 are used. 91  */ 92  private static final int ZERO_COPY_CHUNK_SIZE = 512 * 1024; 93  94  private ByteStreams() {} 95  96  /** 97  * Copies all bytes from the input stream to the output stream. Does not close or flush either 98  * stream. 99  * 100  * @param from the input stream to read from 101  * @param to the output stream to write to 102  * @return the number of bytes copied 103  * @throws IOException if an I/O error occurs 104  */ 105  @CanIgnoreReturnValue 106  public static long copy(InputStream from, OutputStream to) throws IOException { 107  checkNotNull(from); 108  checkNotNull(to); 109  byte[] buf = createBuffer(); 110  long total = 0; 111  while (true) { 112  int r = from.read(buf); 113  if (r == -1) { 114  break; 115  } 116  to.write(buf, 0, r); 117  total += r; 118  } 119  return total; 120  } 121  122  /** 123  * Copies all bytes from the readable channel to the writable channel. Does not close or flush 124  * either channel. 125  * 126  * @param from the readable channel to read from 127  * @param to the writable channel to write to 128  * @return the number of bytes copied 129  * @throws IOException if an I/O error occurs 130  */ 131  @CanIgnoreReturnValue 132  public static long copy(ReadableByteChannel from, WritableByteChannel to) throws IOException { 133  checkNotNull(from); 134  checkNotNull(to); 135  if (from instanceof FileChannel) { 136  FileChannel sourceChannel = (FileChannel) from; 137  long oldPosition = sourceChannel.position(); 138  long position = oldPosition; 139  long copied; 140  do { 141  copied = sourceChannel.transferTo(position, ZERO_COPY_CHUNK_SIZE, to); 142  position += copied; 143  sourceChannel.position(position); 144  } while (copied > 0 || position < sourceChannel.size()); 145  return position - oldPosition; 146  } 147  148  ByteBuffer buf = ByteBuffer.wrap(createBuffer()); 149  long total = 0; 150  while (from.read(buf) != -1) { 151  Java8Compatibility.flip(buf); 152  while (buf.hasRemaining()) { 153  total += to.write(buf); 154  } 155  Java8Compatibility.clear(buf); 156  } 157  return total; 158  } 159  160  /** Max array length on JVM. */ 161  private static final int MAX_ARRAY_LEN = Integer.MAX_VALUE - 8; 162  163  /** Large enough to never need to expand, given the geometric progression of buffer sizes. */ 164  private static final int TO_BYTE_ARRAY_DEQUE_SIZE = 20; 165  166  /** 167  * Returns a byte array containing the bytes from the buffers already in {@code bufs} (which have 168  * a total combined length of {@code totalLen} bytes) followed by all bytes remaining in the given 169  * input stream. 170  */ 171  private static byte[] toByteArrayInternal(InputStream in, Queue<byte[]> bufs, int totalLen) 172  throws IOException { 173  // Starting with an 8k buffer, double the size of each successive buffer. Buffers are retained 174  // in a deque so that there's no copying between buffers while reading and so all of the bytes 175  // in each new allocated buffer are available for reading from the stream. 176  for (int bufSize = BUFFER_SIZE; 177  totalLen < MAX_ARRAY_LEN; 178  bufSize = IntMath.saturatedMultiply(bufSize, 2)) { 179  byte[] buf = new byte[Math.min(bufSize, MAX_ARRAY_LEN - totalLen)]; 180  bufs.add(buf); 181  int off = 0; 182  while (off < buf.length) { 183  // always OK to fill buf; its size plus the rest of bufs is never more than MAX_ARRAY_LEN 184  int r = in.read(buf, off, buf.length - off); 185  if (r == -1) { 186  return combineBuffers(bufs, totalLen); 187  } 188  off += r; 189  totalLen += r; 190  } 191  } 192  193  // read MAX_ARRAY_LEN bytes without seeing end of stream 194  if (in.read() == -1) { 195  // oh, there's the end of the stream 196  return combineBuffers(bufs, MAX_ARRAY_LEN); 197  } else { 198  throw new OutOfMemoryError("input is too large to fit in a byte array"); 199  } 200  } 201  202  private static byte[] combineBuffers(Queue<byte[]> bufs, int totalLen) { 203  byte[] result = new byte[totalLen]; 204  int remaining = totalLen; 205  while (remaining > 0) { 206  byte[] buf = bufs.remove(); 207  int bytesToCopy = Math.min(remaining, buf.length); 208  int resultOffset = totalLen - remaining; 209  System.arraycopy(buf, 0, result, resultOffset, bytesToCopy); 210  remaining -= bytesToCopy; 211  } 212  return result; 213  } 214  215  /** 216  * Reads all bytes from an input stream into a byte array. Does not close the stream. 217  * 218  * @param in the input stream to read from 219  * @return a byte array containing all the bytes from the stream 220  * @throws IOException if an I/O error occurs 221  */ 222  public static byte[] toByteArray(InputStream in) throws IOException { 223  checkNotNull(in); 224  return toByteArrayInternal(in, new ArrayDeque<byte[]>(TO_BYTE_ARRAY_DEQUE_SIZE), 0); 225  } 226  227  /** 228  * Reads all bytes from an input stream into a byte array. The given expected size is used to 229  * create an initial byte array, but if the actual number of bytes read from the stream differs, 230  * the correct result will be returned anyway. 231  */ 232  static byte[] toByteArray(InputStream in, long expectedSize) throws IOException { 233  checkArgument(expectedSize >= 0, "expectedSize (%s) must be non-negative", expectedSize); 234  if (expectedSize > MAX_ARRAY_LEN) { 235  throw new OutOfMemoryError(expectedSize + " bytes is too large to fit in a byte array"); 236  } 237  238  byte[] bytes = new byte[(int) expectedSize]; 239  int remaining = (int) expectedSize; 240  241  while (remaining > 0) { 242  int off = (int) expectedSize - remaining; 243  int read = in.read(bytes, off, remaining); 244  if (read == -1) { 245  // end of stream before reading expectedSize bytes 246  // just return the bytes read so far 247  return Arrays.copyOf(bytes, off); 248  } 249  remaining -= read; 250  } 251  252  // bytes is now full 253  int b = in.read(); 254  if (b == -1) { 255  return bytes; 256  } 257  258  // the stream was longer, so read the rest normally 259  Queue<byte[]> bufs = new ArrayDeque<byte[]>(TO_BYTE_ARRAY_DEQUE_SIZE + 2); 260  bufs.add(bytes); 261  bufs.add(new byte[] {(byte) b}); 262  return toByteArrayInternal(in, bufs, bytes.length + 1); 263  } 264  265  /** 266  * Reads and discards data from the given {@code InputStream} until the end of the stream is 267  * reached. Returns the total number of bytes read. Does not close the stream. 268  * 269  * @since 20.0 270  */ 271  @CanIgnoreReturnValue 272  @Beta 273  public static long exhaust(InputStream in) throws IOException { 274  long total = 0; 275  long read; 276  byte[] buf = createBuffer(); 277  while ((read = in.read(buf)) != -1) { 278  total += read; 279  } 280  return total; 281  } 282  283  /** 284  * Returns a new {@link ByteArrayDataInput} instance to read from the {@code bytes} array from the 285  * beginning. 286  */ 287  @Beta 288  public static ByteArrayDataInput newDataInput(byte[] bytes) { 289  return newDataInput(new ByteArrayInputStream(bytes)); 290  } 291  292  /** 293  * Returns a new {@link ByteArrayDataInput} instance to read from the {@code bytes} array, 294  * starting at the given position. 295  * 296  * @throws IndexOutOfBoundsException if {@code start} is negative or greater than the length of 297  * the array 298  */ 299  @Beta 300  public static ByteArrayDataInput newDataInput(byte[] bytes, int start) { 301  checkPositionIndex(start, bytes.length); 302  return newDataInput(new ByteArrayInputStream(bytes, start, bytes.length - start)); 303  } 304  305  /** 306  * Returns a new {@link ByteArrayDataInput} instance to read from the given {@code 307  * ByteArrayInputStream}. The given input stream is not reset before being read from by the 308  * returned {@code ByteArrayDataInput}. 309  * 310  * @since 17.0 311  */ 312  @Beta 313  public static ByteArrayDataInput newDataInput(ByteArrayInputStream byteArrayInputStream) { 314  return new ByteArrayDataInputStream(checkNotNull(byteArrayInputStream)); 315  } 316  317  private static class ByteArrayDataInputStream implements ByteArrayDataInput { 318  final DataInput input; 319  320  ByteArrayDataInputStream(ByteArrayInputStream byteArrayInputStream) { 321  this.input = new DataInputStream(byteArrayInputStream); 322  } 323  324  @Override 325  public void readFully(byte b[]) { 326  try { 327  input.readFully(b); 328  } catch (IOException e) { 329  throw new IllegalStateException(e); 330  } 331  } 332  333  @Override 334  public void readFully(byte b[], int off, int len) { 335  try { 336  input.readFully(b, off, len); 337  } catch (IOException e) { 338  throw new IllegalStateException(e); 339  } 340  } 341  342  @Override 343  public int skipBytes(int n) { 344  try { 345  return input.skipBytes(n); 346  } catch (IOException e) { 347  throw new IllegalStateException(e); 348  } 349  } 350  351  @Override 352  public boolean readBoolean() { 353  try { 354  return input.readBoolean(); 355  } catch (IOException e) { 356  throw new IllegalStateException(e); 357  } 358  } 359  360  @Override 361  public byte readByte() { 362  try { 363  return input.readByte(); 364  } catch (EOFException e) { 365  throw new IllegalStateException(e); 366  } catch (IOException impossible) { 367  throw new AssertionError(impossible); 368  } 369  } 370  371  @Override 372  public int readUnsignedByte() { 373  try { 374  return input.readUnsignedByte(); 375  } catch (IOException e) { 376  throw new IllegalStateException(e); 377  } 378  } 379  380  @Override 381  public short readShort() { 382  try { 383  return input.readShort(); 384  } catch (IOException e) { 385  throw new IllegalStateException(e); 386  } 387  } 388  389  @Override 390  public int readUnsignedShort() { 391  try { 392  return input.readUnsignedShort(); 393  } catch (IOException e) { 394  throw new IllegalStateException(e); 395  } 396  } 397  398  @Override 399  public char readChar() { 400  try { 401  return input.readChar(); 402  } catch (IOException e) { 403  throw new IllegalStateException(e); 404  } 405  } 406  407  @Override 408  public int readInt() { 409  try { 410  return input.readInt(); 411  } catch (IOException e) { 412  throw new IllegalStateException(e); 413  } 414  } 415  416  @Override 417  public long readLong() { 418  try { 419  return input.readLong(); 420  } catch (IOException e) { 421  throw new IllegalStateException(e); 422  } 423  } 424  425  @Override 426  public float readFloat() { 427  try { 428  return input.readFloat(); 429  } catch (IOException e) { 430  throw new IllegalStateException(e); 431  } 432  } 433  434  @Override 435  public double readDouble() { 436  try { 437  return input.readDouble(); 438  } catch (IOException e) { 439  throw new IllegalStateException(e); 440  } 441  } 442  443  @Override 444  @CheckForNull 445  public String readLine() { 446  try { 447  return input.readLine(); 448  } catch (IOException e) { 449  throw new IllegalStateException(e); 450  } 451  } 452  453  @Override 454  public String readUTF() { 455  try { 456  return input.readUTF(); 457  } catch (IOException e) { 458  throw new IllegalStateException(e); 459  } 460  } 461  } 462  463  /** Returns a new {@link ByteArrayDataOutput} instance with a default size. */ 464  @Beta 465  public static ByteArrayDataOutput newDataOutput() { 466  return newDataOutput(new ByteArrayOutputStream()); 467  } 468  469  /** 470  * Returns a new {@link ByteArrayDataOutput} instance sized to hold {@code size} bytes before 471  * resizing. 472  * 473  * @throws IllegalArgumentException if {@code size} is negative 474  */ 475  @Beta 476  public static ByteArrayDataOutput newDataOutput(int size) { 477  // When called at high frequency, boxing size generates too much garbage, 478  // so avoid doing that if we can. 479  if (size < 0) { 480  throw new IllegalArgumentException(String.format("Invalid size: %s", size)); 481  } 482  return newDataOutput(new ByteArrayOutputStream(size)); 483  } 484  485  /** 486  * Returns a new {@link ByteArrayDataOutput} instance which writes to the given {@code 487  * ByteArrayOutputStream}. The given output stream is not reset before being written to by the 488  * returned {@code ByteArrayDataOutput} and new data will be appended to any existing content. 489  * 490  * <p>Note that if the given output stream was not empty or is modified after the {@code 491  * ByteArrayDataOutput} is created, the contract for {@link ByteArrayDataOutput#toByteArray} will 492  * not be honored (the bytes returned in the byte array may not be exactly what was written via 493  * calls to {@code ByteArrayDataOutput}). 494  * 495  * @since 17.0 496  */ 497  @Beta 498  public static ByteArrayDataOutput newDataOutput(ByteArrayOutputStream byteArrayOutputStream) { 499  return new ByteArrayDataOutputStream(checkNotNull(byteArrayOutputStream)); 500  } 501  502  private static class ByteArrayDataOutputStream implements ByteArrayDataOutput { 503  504  final DataOutput output; 505  final ByteArrayOutputStream byteArrayOutputStream; 506  507  ByteArrayDataOutputStream(ByteArrayOutputStream byteArrayOutputStream) { 508  this.byteArrayOutputStream = byteArrayOutputStream; 509  output = new DataOutputStream(byteArrayOutputStream); 510  } 511  512  @Override 513  public void write(int b) { 514  try { 515  output.write(b); 516  } catch (IOException impossible) { 517  throw new AssertionError(impossible); 518  } 519  } 520  521  @Override 522  public void write(byte[] b) { 523  try { 524  output.write(b); 525  } catch (IOException impossible) { 526  throw new AssertionError(impossible); 527  } 528  } 529  530  @Override 531  public void write(byte[] b, int off, int len) { 532  try { 533  output.write(b, off, len); 534  } catch (IOException impossible) { 535  throw new AssertionError(impossible); 536  } 537  } 538  539  @Override 540  public void writeBoolean(boolean v) { 541  try { 542  output.writeBoolean(v); 543  } catch (IOException impossible) { 544  throw new AssertionError(impossible); 545  } 546  } 547  548  @Override 549  public void writeByte(int v) { 550  try { 551  output.writeByte(v); 552  } catch (IOException impossible) { 553  throw new AssertionError(impossible); 554  } 555  } 556  557  @Override 558  public void writeBytes(String s) { 559  try { 560  output.writeBytes(s); 561  } catch (IOException impossible) { 562  throw new AssertionError(impossible); 563  } 564  } 565  566  @Override 567  public void writeChar(int v) { 568  try { 569  output.writeChar(v); 570  } catch (IOException impossible) { 571  throw new AssertionError(impossible); 572  } 573  } 574  575  @Override 576  public void writeChars(String s) { 577  try { 578  output.writeChars(s); 579  } catch (IOException impossible) { 580  throw new AssertionError(impossible); 581  } 582  } 583  584  @Override 585  public void writeDouble(double v) { 586  try { 587  output.writeDouble(v); 588  } catch (IOException impossible) { 589  throw new AssertionError(impossible); 590  } 591  } 592  593  @Override 594  public void writeFloat(float v) { 595  try { 596  output.writeFloat(v); 597  } catch (IOException impossible) { 598  throw new AssertionError(impossible); 599  } 600  } 601  602  @Override 603  public void writeInt(int v) { 604  try { 605  output.writeInt(v); 606  } catch (IOException impossible) { 607  throw new AssertionError(impossible); 608  } 609  } 610  611  @Override 612  public void writeLong(long v) { 613  try { 614  output.writeLong(v); 615  } catch (IOException impossible) { 616  throw new AssertionError(impossible); 617  } 618  } 619  620  @Override 621  public void writeShort(int v) { 622  try { 623  output.writeShort(v); 624  } catch (IOException impossible) { 625  throw new AssertionError(impossible); 626  } 627  } 628  629  @Override 630  public void writeUTF(String s) { 631  try { 632  output.writeUTF(s); 633  } catch (IOException impossible) { 634  throw new AssertionError(impossible); 635  } 636  } 637  638  @Override 639  public byte[] toByteArray() { 640  return byteArrayOutputStream.toByteArray(); 641  } 642  } 643  644  private static final OutputStream NULL_OUTPUT_STREAM = 645  new OutputStream() { 646  /** Discards the specified byte. */ 647  @Override 648  public void write(int b) {} 649  650  /** Discards the specified byte array. */ 651  @Override 652  public void write(byte[] b) { 653  checkNotNull(b); 654  } 655  656  /** Discards the specified byte array. */ 657  @Override 658  public void write(byte[] b, int off, int len) { 659  checkNotNull(b); 660  } 661  662  @Override 663  public String toString() { 664  return "ByteStreams.nullOutputStream()"; 665  } 666  }; 667  668  /** 669  * Returns an {@link OutputStream} that simply discards written bytes. 670  * 671  * @since 14.0 (since 1.0 as com.google.common.io.NullOutputStream) 672  */ 673  @Beta 674  public static OutputStream nullOutputStream() { 675  return NULL_OUTPUT_STREAM; 676  } 677  678  /** 679  * Wraps a {@link InputStream}, limiting the number of bytes which can be read. 680  * 681  * @param in the input stream to be wrapped 682  * @param limit the maximum number of bytes to be read 683  * @return a length-limited {@link InputStream} 684  * @since 14.0 (since 1.0 as com.google.common.io.LimitInputStream) 685  */ 686  @Beta 687  public static InputStream limit(InputStream in, long limit) { 688  return new LimitedInputStream(in, limit); 689  } 690  691  private static final class LimitedInputStream extends FilterInputStream { 692  693  private long left; 694  private long mark = -1; 695  696  LimitedInputStream(InputStream in, long limit) { 697  super(in); 698  checkNotNull(in); 699  checkArgument(limit >= 0, "limit must be non-negative"); 700  left = limit; 701  } 702  703  @Override 704  public int available() throws IOException { 705  return (int) Math.min(in.available(), left); 706  } 707  708  // it's okay to mark even if mark isn't supported, as reset won't work 709  @Override 710  public synchronized void mark(int readLimit) { 711  in.mark(readLimit); 712  mark = left; 713  } 714  715  @Override 716  public int read() throws IOException { 717  if (left == 0) { 718  return -1; 719  } 720  721  int result = in.read(); 722  if (result != -1) { 723  --left; 724  } 725  return result; 726  } 727  728  @Override 729  public int read(byte[] b, int off, int len) throws IOException { 730  if (left == 0) { 731  return -1; 732  } 733  734  len = (int) Math.min(len, left); 735  int result = in.read(b, off, len); 736  if (result != -1) { 737  left -= result; 738  } 739  return result; 740  } 741  742  @Override 743  public synchronized void reset() throws IOException { 744  if (!in.markSupported()) { 745  throw new IOException("Mark not supported"); 746  } 747  if (mark == -1) { 748  throw new IOException("Mark not set"); 749  } 750  751  in.reset(); 752  left = mark; 753  } 754  755  @Override 756  public long skip(long n) throws IOException { 757  n = Math.min(n, left); 758  long skipped = in.skip(n); 759  left -= skipped; 760  return skipped; 761  } 762  } 763  764  /** 765  * Attempts to read enough bytes from the stream to fill the given byte array, with the same 766  * behavior as {@link DataInput#readFully(byte[])}. Does not close the stream. 767  * 768  * @param in the input stream to read from. 769  * @param b the buffer into which the data is read. 770  * @throws EOFException if this stream reaches the end before reading all the bytes. 771  * @throws IOException if an I/O error occurs. 772  */ 773  @Beta 774  public static void readFully(InputStream in, byte[] b) throws IOException { 775  readFully(in, b, 0, b.length); 776  } 777  778  /** 779  * Attempts to read {@code len} bytes from the stream into the given array starting at {@code 780  * off}, with the same behavior as {@link DataInput#readFully(byte[], int, int)}. Does not close 781  * the stream. 782  * 783  * @param in the input stream to read from. 784  * @param b the buffer into which the data is read. 785  * @param off an int specifying the offset into the data. 786  * @param len an int specifying the number of bytes to read. 787  * @throws EOFException if this stream reaches the end before reading all the bytes. 788  * @throws IOException if an I/O error occurs. 789  */ 790  @Beta 791  public static void readFully(InputStream in, byte[] b, int off, int len) throws IOException { 792  int read = read(in, b, off, len); 793  if (read != len) { 794  throw new EOFException( 795  "reached end of stream after reading " + read + " bytes; " + len + " bytes expected"); 796  } 797  } 798  799  /** 800  * Discards {@code n} bytes of data from the input stream. This method will block until the full 801  * amount has been skipped. Does not close the stream. 802  * 803  * @param in the input stream to read from 804  * @param n the number of bytes to skip 805  * @throws EOFException if this stream reaches the end before skipping all the bytes 806  * @throws IOException if an I/O error occurs, or the stream does not support skipping 807  */ 808  @Beta 809  public static void skipFully(InputStream in, long n) throws IOException { 810  long skipped = skipUpTo(in, n); 811  if (skipped < n) { 812  throw new EOFException( 813  "reached end of stream after skipping " + skipped + " bytes; " + n + " bytes expected"); 814  } 815  } 816  817  /** 818  * Discards up to {@code n} bytes of data from the input stream. This method will block until 819  * either the full amount has been skipped or until the end of the stream is reached, whichever 820  * happens first. Returns the total number of bytes skipped. 821  */ 822  static long skipUpTo(InputStream in, final long n) throws IOException { 823  long totalSkipped = 0; 824  // A buffer is allocated if skipSafely does not skip any bytes. 825  byte[] buf = null; 826  827  while (totalSkipped < n) { 828  long remaining = n - totalSkipped; 829  long skipped = skipSafely(in, remaining); 830  831  if (skipped == 0) { 832  // Do a buffered read since skipSafely could return 0 repeatedly, for example if 833  // in.available() always returns 0 (the default). 834  int skip = (int) Math.min(remaining, BUFFER_SIZE); 835  if (buf == null) { 836  // Allocate a buffer bounded by the maximum size that can be requested, for 837  // example an array of BUFFER_SIZE is unnecessary when the value of remaining 838  // is smaller. 839  buf = new byte[skip]; 840  } 841  if ((skipped = in.read(buf, 0, skip)) == -1) { 842  // Reached EOF 843  break; 844  } 845  } 846  847  totalSkipped += skipped; 848  } 849  850  return totalSkipped; 851  } 852  853  /** 854  * Attempts to skip up to {@code n} bytes from the given input stream, but not more than {@code 855  * in.available()} bytes. This prevents {@code FileInputStream} from skipping more bytes than 856  * actually remain in the file, something that it {@linkplain java.io.FileInputStream#skip(long) 857  * specifies} it can do in its Javadoc despite the fact that it is violating the contract of 858  * {@code InputStream.skip()}. 859  */ 860  private static long skipSafely(InputStream in, long n) throws IOException { 861  int available = in.available(); 862  return available == 0 ? 0 : in.skip(Math.min(available, n)); 863  } 864  865  /** 866  * Process the bytes of the given input stream using the given processor. 867  * 868  * @param input the input stream to process 869  * @param processor the object to which to pass the bytes of the stream 870  * @return the result of the byte processor 871  * @throws IOException if an I/O error occurs 872  * @since 14.0 873  */ 874  @Beta 875  @CanIgnoreReturnValue // some processors won't return a useful result 876  @ParametricNullness 877  public static <T extends @Nullable Object> T readBytes( 878  InputStream input, ByteProcessor<T> processor) throws IOException { 879  checkNotNull(input); 880  checkNotNull(processor); 881  882  byte[] buf = createBuffer(); 883  int read; 884  do { 885  read = input.read(buf); 886  } while (read != -1 && processor.processBytes(buf, 0, read)); 887  return processor.getResult(); 888  } 889  890  /** 891  * Reads some bytes from an input stream and stores them into the buffer array {@code b}. This 892  * method blocks until {@code len} bytes of input data have been read into the array, or end of 893  * file is detected. The number of bytes read is returned, possibly zero. Does not close the 894  * stream. 895  * 896  * <p>A caller can detect EOF if the number of bytes read is less than {@code len}. All subsequent 897  * calls on the same stream will return zero. 898  * 899  * <p>If {@code b} is null, a {@code NullPointerException} is thrown. If {@code off} is negative, 900  * or {@code len} is negative, or {@code off+len} is greater than the length of the array {@code 901  * b}, then an {@code IndexOutOfBoundsException} is thrown. If {@code len} is zero, then no bytes 902  * are read. Otherwise, the first byte read is stored into element {@code b[off]}, the next one 903  * into {@code b[off+1]}, and so on. The number of bytes read is, at most, equal to {@code len}. 904  * 905  * @param in the input stream to read from 906  * @param b the buffer into which the data is read 907  * @param off an int specifying the offset into the data 908  * @param len an int specifying the number of bytes to read 909  * @return the number of bytes read 910  * @throws IOException if an I/O error occurs 911  * @throws IndexOutOfBoundsException if {@code off} is negative, if {@code len} is negative, or if 912  * {@code off + len} is greater than {@code b.length} 913  */ 914  @Beta 915  @CanIgnoreReturnValue 916  // Sometimes you don't care how many bytes you actually read, I guess. 917  // (You know that it's either going to read len bytes or stop at EOF.) 918  public static int read(InputStream in, byte[] b, int off, int len) throws IOException { 919  checkNotNull(in); 920  checkNotNull(b); 921  if (len < 0) { 922  throw new IndexOutOfBoundsException(String.format("len (%s) cannot be negative", len)); 923  } 924  checkPositionIndexes(off, off + len, b.length); 925  int total = 0; 926  while (total < len) { 927  int result = in.read(b, off + total, len - total); 928  if (result == -1) { 929  break; 930  } 931  total += result; 932  } 933  return total; 934  } 935 }