android/guava/src/com/google/common/io/CharStreams.java
@CanIgnoreReturnValue
  public static long copy(Readable from, Appendable to) throws IOException {
    // The most common case is that from is a Reader (like InputStreamReader or StringReader) so
    // take advantage of that.
    if (from instanceof Reader) {
      // optimize for common output types which are optimized to deal with char[]
      if (to instanceof StringBuilder) {
        return copyReaderToBuilder((Reader) from, (StringBuilder) to);
      } else {
        return copyReaderToWriter((Reader) from, asWriter(to));
      }
    } else {
      checkNotNull(from);
      checkNotNull(to);
      long total = 0;
      CharBuffer buf = createBuffer();
      while (from.read(buf) != -1) {
        buf.flip();
        to.append(buf);
        total += buf.remaining();
        buf.clear();
      }
      return total;
    }
  }
@CanIgnoreReturnValue
  public static long copy(Readable from, Appendable to) throws IOException {
    // The most common case is that from is a Reader (like InputStreamReader or StringReader) so
    // take advantage of that.
    if (from instanceof Reader) {
      // optimize for common output types which are optimized to deal with char[]
      if (to instanceof StringBuilder) {
        return copyReaderToBuilder((Reader) from, (StringBuilder) to);
      } else {
        return copyReaderToWriter((Reader) from, asWriter(to));
      }
    } else {
      checkNotNull(from);
      checkNotNull(to);
      long total = 0;
      CharBuffer buf = createBuffer();
      while (from.read(buf) != -1) {
        buf.flip();
        to.append(buf);
        total += buf.remaining();
        buf.clear();
      }
      return total;
    }
  }
Copies all characters between the {@link Readable} and {@link Appendable} objects. Does not
close or flush either object.

@param from the object to read from
@param to the object to write to
@return the number of characters copied
@throws IOException if an I/O error occurs