简体   繁体   中英

Is it possible to close a Reader without closing the stream?

I have a method which accepts an InputStream (of binary data) and serializes it to XML. In order to do so, it wraps the stream with a base64 encoder and a Reader to convert it to character data. However, since the InputStream is passed in as a parameter, I would consider it a harmful side effect to close the stream, and the contract for Reader.close() says it would do just that. If I don't close the reader, the compiler warns me that I have a

Resource leak: reader is never closed

So, I can add a @SuppressWarnings( "resource" ) to the reader declaration, but is that the right thing to do? Am I missing something?

Here is the actual code:

/**
 * Writes base64 encoded text read from the binary stream.
 * 
 * @param binaryStream
 *            The binary stream to write from
 * @return <code>this</code> XmlWriter (for chaining)
 * @throws IOException
 */
public XmlWriter binary( InputStream binaryStream ) throws IOException {
    Reader reader = new InputStreamReader( 
            new Base64InputStream( binaryStream, true, base64LineLength, base64LineSeparator.getBytes( charset ) ) );
    int bufferSize = 2048;
    int charsRead;
    char[] buffer = new char[bufferSize];
    while ( (charsRead = reader.read( buffer, 0, bufferSize )) >= 0 ) {
        writer.write( buffer, 0, charsRead );
    }

    return this;
}

If you are a happy Java 7 user, try this:

try(InputStream binaryStream = /* ... */) {
    xmlWriter.binary(binaryStream);
}

and stream is closed for you. If you can't use Java 7, I agree that it's not the responsibility of binary() method to close() the stream. Just ignore the warning and don't let tools drive your design. It's fine.

As a last resort you can write a lightweight Reader wrapper ignoring close() , but I don't advice it as it makes following the program flow harder.

Also let Apache Commons IO help you with IOUtils.copy() :

public XmlWriter binary( InputStream binaryStream ) throws IOException {
    Reader reader = new InputStreamReader( 
            new Base64InputStream( binaryStream, true, base64LineLength, base64LineSeparator.getBytes( charset ) ) );
    IOUtils.copy(reader, writer);
    return this;
}

This is a perhaps a "feature" in the way Base64InputStream work that even though you specify the length to read, it will close the underlying stream if you close it when clearly you intended not to read the whole stream.

You could wrap the binaryStream in an InputStream which ignores the close, or you could suppress the warning as you have.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM