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).
}
  /**
   * Copies all bytes from the readable channel to the writable channel. Does not close or flush
   * either channel.
   *
   * @param from the readable channel to read from
   * @param to the writable channel to write to
   * @return the number of bytes copied
   * @throws IOException if an I/O error occurs
   */
  @CanIgnoreReturnValue
  public static long copy(ReadableByteChannel from, WritableByteChannel to) throws IOException {
    checkNotNull(from);
    checkNotNull(to);
    if (from instanceof FileChannel) {
      FileChannel sourceChannel = (FileChannel) from;
      long oldPosition = sourceChannel.position();
      long position = oldPosition;
      long copied;
      do {
        copied = sourceChannel.transferTo(position, ZERO_COPY_CHUNK_SIZE, to);
        position += copied;
        sourceChannel.position(position);
      } while (copied > 0 || position < sourceChannel.size());
      return position - oldPosition;
    }
    ByteBuffer buf = ByteBuffer.wrap(createBuffer());
    long total = 0;
    while (from.read(buf) != -1) {
      buf.flip();