尝试使用资源和System.in

时间:2014-04-13 09:52:23

标签: java stream stdin try-with-resources

好的,这可能不是最好的问题,但是我坚持下去并且无法在网上找到答案。

此代码第二次不会从标准输入读取:

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());
}

我知道java的try-with-resources以递归方式关闭链中的所有流,因此在第一次阅读System.in之后关闭。那有什么好的解决方法吗?或者我应该自己处理流关闭吗?

UPD: 我试图处理关闭自己的流(这是java6风格)。如果有人感兴趣的话,这里是code。但是我注意到这种关闭链的行为不是来自try-with-resources bur而是来自close方法的实现。所以我没有从那次尝试中获得任何好处。

我选择了fge的解决方案,因为它是最冗长的解决方案。它直接对我有用。

总而言之,我觉得很奇怪,java没有开箱即用的解决方案,因为系统流不应该被关闭。

4 个答案:

答案 0 :(得分:1)

一种解决方法是创建一个自定义InputStream类,该类将委托给另一个,除了它本身关闭时不会.close()。如:

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();
    }
}

请注意,在您的情况下,一个可能更简单的解决方案是扩展InputStreamReader,因为该类不是final而只是覆盖.close()

答案 1 :(得分:1)

我认为这个问题比try-with-resources更普遍,因为其他人可能会使用旧版本的Java并自己关闭BufferedReader。这会让你处于和现在一样的情况 我找到了relevant SO question这个更一般的情况。给出的答案是使用Apache Commons IO,它有一个名为CloseShieldInputStream的流代理。如果这是您将使用的Commons IO中唯一的东西,您也可以考虑自己编写代理类,而不是依赖于像Commons IO这样的大型库。

答案 2 :(得分:1)

这确实是一个小问题。我不知道,如果公共库(Apache Commons IO,Google Guava,...)中存在某些解决方案,但您可以自己编写一个处理此问题的简单类。

编写一个InputStream的类并包装InputStream,通过将调用委托给包装的流来覆盖所有公共方法,但close方法除外,什么都不做。

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
}

在此类的实例中包装System.in将解决您的问题。

答案 3 :(得分:0)

这是一个老问题,但这是一个更简洁的解决方案:

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

这样可以通过将System.in空格式InputStreamReader方法传递给close()的构造函数来确保不会关闭BufferedReader