【问题标题】:Try-with-resources and System.inTry-with-resources 和 System.in
【发布时间】:2014-04-13 09:52:22
【问题描述】:

好的,这可能不是最好的问题,但我被它困住了,无法在网上找到答案。

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

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 被关闭。有什么好的解决方法吗?或者我真的应该自己处理流关闭吗?

更新: 我试图处理关闭自己的流(即 java6 风格)。如果有人感兴趣,这里是code。但是我注意到这种闭链行为不是来自资源尝试,而是来自于关闭方法的实现。所以我没有从那次尝试中赢得任何东西。

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

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

【问题讨论】:

  • 您可以创建自己的InputStream 类,它不会关闭.close() 上的底层资源;虽然这违反了.close() 合同
  • 或者你可以避免在这种情况下使用 try-with-resources,因为你不希望流被关闭,这就是 try-with-resources 所做的。

标签: java stream stdin try-with-resources


【解决方案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()

【讨论】:

  • 我认为 OP 知道这一点。他正在寻求解决方法。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    这确实是个小问题。我不知道公共库(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 包装在此类的实例中将解决您的问题。

    【讨论】:

      【解决方案4】:

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

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

      这确保System.in 不会被关闭,方法是将带有空覆盖的close() 方法的InputStreamReader 传递给BufferedReader 的构造函数。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-05-05
        • 1970-01-01
        • 2020-12-02
        • 2014-12-18
        • 2013-07-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多