skipUpTo helpfully falls back from skip invocations which return zero to invoke a read into a buffer.

The current implementation has two inefficiencies which cause unexpected performance degradation in tight loops, especially when a small number of bytes are requested:

1. In many cases skipSafely is able to skip all the requested bytes, there's no need to allocate a read buffer
2. The caller only requests a few bytes are skipped. Calling `ByteStreams.skipFully(stream, 32)` always allocates a 8192 byte buffer.

Proposed solution:
Defer buffer allocation until it is needed, using the minimum of the requested size and BUFFER_SIZE. This reduces allocation pressure in all cases of small skip values, as well as streams that report nonzero bytes available (assuming skip returns a positive value).
*
   * @param in the input stream to read from
   * @param b the buffer into which the data is read
   * @param off an int specifying the offset into the data
   * @param len an int specifying the number of bytes to read
   * @return the number of bytes read
   * @throws IOException if an I/O error occurs
   */
  @Beta
  @CanIgnoreReturnValue
  
  
  public static int read(InputStream in, byte[] b, int off, int len) throws IOException {
    checkNotNull(in);
    checkNotNull(b);
    if (len < 0) {
      throw new IndexOutOfBoundsException("len is negative");
    }
    int total = 0;
    while (total < len) {
      int result = in.read(b, off + total, len - total);
      if (result == -1) {
        break;
      }
      total += result;
    }
    return total;
  }
}