Hi Pavel,
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.
Welcome, unfortunately I did not manage it to check those on the JDK9
code base due the fact, that the NetBeans project does not work with the
modularized codebase jet.
I think more and more about your initial suggestion of introducing a 'copyTo'
method directly into the types:
InputStream, OutputStream, Readable and Appendable
Having a "copyTo" method on InputStream and Readable was indeed my fist
idea to have. Also to have a "copyFrom" method on the OutputStream and
Appendable was then a natural fit. Looking at those methods it became
clear to me that in fact we would have a the same code on either
InputStream and OutputStream or Readable and Appendable.
Of course for OutputStream we could also have something like:
public long copyFrom(InputStream source) throws IOException {
return source.copyTo(this);
}
For the Appendable could it be the same same with a Readable as the
source in that case.
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:
Should those methods also be on the FilterInput- and OutputStream?
/**
* {@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
I like that solution almost more then having a separate utility class
though.
I'm not quit sure about the impact on may already existing customer code
that had implemented such a method without declaring a IOException for
example. In this case the existing code would may break? (as a comment
of Alan Bateman earlier before)
-Patrick