Domanda

Ok, here is a probably not the best question, but I'm stuck with it and can't find answer to this on the net.

This code won't read from standard input the second time:

try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in)))
{
    input = br.readLine();
}
catch (final Exception e)
{
    System.err.println("Read from STDIN failed: " + e.getMessage());
}
// do some processing
try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in)))
{
    input = br.readLine();
}
catch (final Exception e)
{
    System.err.println("Read from STDIN failed: " + e.getMessage());
}

I know java's try-with-resources recursively closes all streams in the chain, so after the first reading System.in is closed. Is there any good workaround for that? Or should I really handle stream closing myself?

upd: I tried to handle the stream closing myself (that is java6-style). Here's a code if somebody's interested. But I noticed that this chain-closing behaviour comes not from try-with-resources bur rather from the implementation of close-methods. So I didn't win anything from that attempt.

I pick fge's solution because it's the most verbose one. It worked for me directly.

All in all it seems quite strange to me, that java doesn't have such solution out of the box since there are system streams which shouldn't be closed.

È stato utile?

Soluzione

One workaround would be to create a custom InputStream class which would delegate to another one, except that it wouldn't .close() it when itself is closed. As in:

public class ForwardingInputStream
    extends InputStream
{
    private final InputStream in;
    private final boolean closeWrapped;

    public ForwardingInputStream(final InputStream in, final boolean closeWrapped)
    {
        this.in = in;
        this.closeWrapped = closeWrapped;
    }

    public ForwardingInputStream(final InputStream in)
    {
        this(in, false);
    }

    @Override
    public int read()
        throws IOException
    {
        return in.read();
    }

    @Override
    public int read(final byte[] b)
        throws IOException
    {
        return in.read(b);
    }

    @Override
    public int read(final byte[] b, final int off, final int len)
        throws IOException
    {
        return in.read(b, off, len);
    }

    @Override
    public long skip(final long n)
        throws IOException
    {
        return in.skip(n);
    }

    @Override
    public int available()
        throws IOException
    {
        return in.available();
    }

    @Override
    public void close()
        throws IOException
    {
        if (closeWrapped)
            in.close();
    }

    @Override
    public synchronized void mark(final int readlimit)
    {
        in.mark(readlimit);
    }

    @Override
    public synchronized void reset()
        throws IOException
    {
        in.reset();
    }

    @Override
    public boolean markSupported()
    {
        return in.markSupported();
    }
}

Note that a probably easier solution in your case would be to extend InputStreamReader as the class is not final and just override .close().

Altri suggerimenti

I figured that this issue would be more general than try-with-resources in that others might use an older version of Java and close the BufferedReader themselves. That would get you in the same situation as you have now.
I found a relevant SO question for this more general case. The answer given there is to use Apache Commons IO, which has a stream proxy called CloseShieldInputStream. If this is the only thing from Commons IO you would use, you could also consider writing the proxy class yourself instead of depending on a large library like Commons IO.

This is indeed a little problem. I do not know, if some solutions exist in the common libraries (Apache Commons IO, Google Guava, ...), but you could write a simple class handling this issue yourself.

Write a class that is an InputStream and that wraps an InputStream, overriding all public methods by delegating the call to the wrapped stream, with the exception of the close method, that does nothing at all.

public final class NonClosingInputStream extends InputStream {
    private final InputStream wrappedStream;
    public NonClosingInputStream(final InputStream wrappedStream) {
        this.wrappedStream = Objects.requireNonNull(wrappedStream);
    }
    @Override
    public void close() {
        // do nothing
    }
    // all other methods
}

Wrapping System.in in an instance of this class will solve your problem.

This is an old question, but here is a more concise solution:

try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in)
{public void close() throws IOException {}})) {
    input = br.readLine();
}

This ensures System.in won't be closed by passing an InputStreamReader with an empty overridden close() method to the constructor of BufferedReader.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top