【问题标题】:Am I closing my input stream correctly in Java?我是否在 Java 中正确关闭了我的输入流?
【发布时间】:2020-08-27 12:25:35
【问题描述】:

我创建了一个扩展 InputStream 的类,以便我可以计算正在读取的字节数,并在超出我定义的最大限制时抛出异常。

这是我的课:

    public class LimitedSizeInputStream extends InputStream
    {

        private final InputStream original;
        private final long maxSize;
        private long total;

        public LimitedSizeInputStream(InputStream original, long maxSize)
        {
            this.original = original;
            this.maxSize = maxSize;
        }

        @Override
        public int read() throws IOException
        {
            int i = original.read();
            if (i >= 0)
            {
                incrementCounter(1);
            }
            return i;
        }

        @Override
        public int read(byte b[]) throws IOException
        {
            return read(b, 0, b.length);
        }

        @Override
        public int read(byte b[], int off, int len) throws IOException
        {
            int i = original.read(b, off, len);
            if (i >= 0)
            {
                incrementCounter(i);
            }
            return i;
        }

        private void incrementCounter(int size) throws IOException
        {
            total += size;
            if (total > maxSize)
            {
                throw new IOException("InputStream exceeded maximum size in bytes.");
            }
        }
    }

这来自:Copy InputStream, abort operation if size exceeds limit,我正在实现一个 Jersey API,如果用户上传的文件太大,该 API 需要失败。

这是我的资源类:

    @POST
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    @Path("/test")
    public Response load(
        @Context HttpServletRequest request,
        @FormDataParam(FILE_FIELD) FormDataBodyPart file)
    {
      if (request.getContentLength() > MAX_FILE_SIZE_IN_BYTES)
        {
            // fail fast handle failure
        }

      try (InputStream stream = new LimitedSizeInputStream(
           file.getValueAs(InputStream.class), MAX_FILE_SIZE_IN_BYTES))
        {
            // some logic
        }
      catch (IOException e)
        {
            // handle failure
        }
}

我在我的尝试资源中包装了 LimitedSizeInputStream,所以我认为流应该正确关闭。我只是有点困惑是否正确处理了关闭,或者我是否在技术上通过 LimitedSizeInputStream 和 file.getValueAs(InputStream.class) 打开两个输入流并且只有一个正在关闭?

【问题讨论】:

  • 看起来你实现了类似于 apache commons BoundedInputStream 的东西。您至少可以查看他们的实施以获得指导。
  • @Deadron 类似但不一样。 BoundedInputStream 不会抛出错误,它只是停止进一步阅读
  • 你应该扩展FilterInputStream。请勿在此处转发问题。

标签: java jersey inputstream dropwizard


【解决方案1】:

try-with-resources 只关闭声明的资源。所以只会关闭metadataStream

您应该在LimitedSizeInputStream 中实现close 方法来关闭原始流。

@Override
public void close() throws IOException {
    original.close();
}

【讨论】:

  • 哦,好吧……这不好。有没有一种优雅的方法来关闭两者而不会使代码混乱?
  • 我添加了所需的代码。那不是乱七八糟的。如果您使用内部输入流来委托读取调用,那么也委托关闭调用是正常的。
  • 但这不会改变行为,所以现在只关闭内部输入流而不是 LimitedSizeInputStream?
  • close 方法的目的是释放任何系统资源。 LimitedSizeInputStream 使用的唯一资源是底层原始 InputStream
【解决方案2】:

如果LimitedSizeInputStream 扩展InputStream 并包装另一个流,那么@areus 的解决方案是最好的。

另一种方法是扩展FilterInputStream,如下所示:

public class LimitedSizeInputStream extends FilterInputStream
{
    private final long maxSize;
    private long total;

    public LimitedSizeInputStream(InputStream original, long maxSize)
    {
        super(original);
        this.original = original;
        this.maxSize = maxSize;
    }

    // use 'this.in' instead of 'this.original'
    // at least one of the 'read' methods needs to be overridden.
}

请注意,FilterInputStream 提供了可能有用的 API 方法的默认实现。

javadoc 提供了默认方法实现的详细信息。

【讨论】:

  • 如果我重写close方法只关闭内部流,LimitedSizeInputStream如何关闭?
  • 如果你使用这种方法,你不需要覆盖关闭。继承的FilterInputStream:close 方法关闭in。这是唯一真正需要关闭的东西。
  • 另一种看待这个问题的方式是您的覆盖close() 关闭了LimitedSizeInputStreamclose 的目的是释放任何资源。属于您的自定义流的唯一资源是它包装的 original 流。如果您直接关闭它,或者通过super.close()委托让超类关闭它,这没有什么区别。
猜你喜欢
  • 2013-09-17
  • 1970-01-01
  • 2020-08-07
  • 2022-11-17
  • 2021-06-26
  • 2021-04-27
  • 1970-01-01
  • 2012-07-01
  • 1970-01-01
相关资源
最近更新 更多