Library enhancement proposal for copying data from/to Reader/Writer InputStream/OutputStream

Pavel Rappo pavel.rappo at oracle.com
Thu Dec 4 16:33:50 UTC 2014


Patrick, thanks a lot for doing this! I've had a look at these usages,  and I
think it's safe to say that in the JDK it has never been required (yet) to
provide a copy method with custom byte array. So let's skip it for now.

I think more and more about your initial suggestion of introducing a 'copyTo'
method directly into the types:

   InputStream, OutputStream, Readable and Appendable

I believe it will suit us a lot more. If we go this way, we can fully utilize
polymorphic calls. Implementations could then provide their own more efficient
solutions. Have a look at this:

/**
 * Reads all remaining bytes from this input stream and writes them to
 * a specified output stream.
 * <p>
 * There are no guarantees on streams state in a case error occurs. Even
 * if method returns normally you can't rely on previously marked positions
 * or the contents of any internal buffers.
 * That said, it is a terminal operation. It is strongly recommended that
 * both streams are promptly closed after this method returns:
 * <pre>{@code
 *     try (InputStream is = ...; OutputStream os = ...;) {
 *         is.read(os);
 *     } catch (IOException e) {
 *         ...
 *     }
 * }</pre>
 * <p>
 * This method may block indefinitely reading from the input stream
 * (or writing to the output stream). The behavior for the case that the
 * input and output streams is <i>asynchronously closed</i> or the thread
 * interrupted during the copy is highly input and output stream
 * system provider specific and therefore not specified.
 *
 * @param  target      the output stream to write to
 *                     ({@code target != null})
 * @return             the number of bytes copied
 * @throws IOException if an I/O error occurs when reading or writing
 *
 * @since 1.9
 */
public long copyTo(OutputStream target) throws IOException {
    Objects.requireNonNull(target, "target");
    int copied = 0;
    byte[] buffer = new byte[8192];
    for (int read; (read = this.read(buffer)) > -1; copied += read) {
        target.write(buffer, 0, read);
    }
    return copied;
}

This method will be defined in java.io.InputStream. And the following methods
will override 'copyTo' in java.io.ByteArrayInputStream and
java.io.BufferedInputStream respectively:

/**
 * {@inheritDoc}
 */
@Override
public synchronized long copyTo(OutputStream target) throws IOException {
    Objects.requireNonNull(target, "target");
    int avail = count - pos;
    target.write(buf, pos, avail);
    return avail;
}

/**
 * {@inheritDoc}
 */
@Override
public synchronized long copyTo(OutputStream target) throws IOException {
    Objects.requireNonNull(target, "target");
    long copied = 0;
    // 1. Get whatever is left unread in the buffer
    if (pos < count) {
        int len = count - pos;
        target.write(getBufIfOpen(), pos, len);
        copied += len;
    }
    // 2. Get everything else directly from the underlying stream
    for (int read; (read = getInIfOpen().read(getBufIfOpen())) > -1;
         copied += read) {
        target.write(getBufIfOpen(), 0, read);
    }
    return copied;
}


1. Please note, that this is not the actual code that will be pushed (if at
   all). It's merely a sketch to illustrate your proposal.
2. The equivalent thing will apply for Readable/Appendable.

-Pavel

> On 2 Dec 2014, at 09:22, Patrick Reinhart <patrick at reini.net> wrote:
> 
> I found around 190 usage references in total of those there are the following 28 references that could use my proposed copy feature and 5 of those use 8192 bytes sized buffers.




More information about the core-libs-dev mailing list