4

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

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

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 风格)。如果有人感兴趣,这是一个代码。但我注意到,这种闭链行为不是来自 try-with-resources bur,而是来自 close-methods 的实现。所以我没有从那次尝试中赢得任何东西。

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

总而言之,这对我来说似乎很奇怪,java没有开箱即用的解决方案,因为存在不应该关闭的系统流。

4

4 回答 4

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并且只是 override .close()

于 2014-04-13T09:56:46.910 回答
1

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

于 2014-04-13T10:05:58.597 回答
1

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

编写一个InputStream包装 an的类,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在此类的实例中将解决您的问题。

于 2014-04-13T10:06:29.880 回答
0

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

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

这确保System.in不会通过将InputStreamReader带有空重写close()方法的BufferedReader.

于 2017-02-28T05:16:25.350 回答