android/guava/src/com/google/common/io/ByteSource.java
public long size() throws IOException {
    Optional<Long> sizeIfKnown = sizeIfKnown();
    if (sizeIfKnown.isPresent()) {
      return sizeIfKnown.get();
    }

    Closer closer = Closer.create();
    try {
      InputStream in = closer.register(openStream());
      return countBySkipping(in);
    } catch (IOException e) {
      // skip may not be supported... at any rate, try reading
    } finally {
      closer.close();
    }

    closer = Closer.create();
    try {
      InputStream in = closer.register(openStream());
      return ByteStreams.exhaust(in);
    } catch (Throwable e) {
      throw closer.rethrow(e);
    } finally {
      closer.close();
    }
  }
public long size() throws IOException {
    Optional<Long> sizeIfKnown = sizeIfKnown();
    if (sizeIfKnown.isPresent()) {
      return sizeIfKnown.get();
    }

    Closer closer = Closer.create();
    try {
      InputStream in = closer.register(openStream());
      return countBySkipping(in);
    } catch (IOException e) {
      // skip may not be supported... at any rate, try reading
    } finally {
      closer.close();
    }

    closer = Closer.create();
    try {
      InputStream in = closer.register(openStream());
      return ByteStreams.exhaust(in);
    } catch (Throwable e) {
      throw closer.rethrow(e);
    } finally {
      closer.close();
    }
  }
Returns the size of this source in bytes, even if doing so requires opening and traversing an
entire stream. To avoid a potentially expensive operation, see {@link #sizeIfKnown}.

<p>The default implementation calls {@link #sizeIfKnown} and returns the value if present. If
absent, it will fall back to a heavyweight operation that will open a stream, read (or {@link
InputStream#skip(long) skip}, if possible) to the end of the stream and return the total number
of bytes that were read.

<p>Note that for some sources that implement {@link #sizeIfKnown} to provide a more efficient
implementation, it is <i>possible</i> that this method will return a different number of bytes
than would be returned by reading all of the bytes (for example, some special files may return
a size of 0 despite actually having content when read).

<p>In either case, for mutable sources such as files, a subsequent read may return a different
number of bytes if the contents are changed.

@throws IOException if an I/O error occurs while reading the size of this source