简体   繁体   中英

Am I closing my input stream correctly in Java?

I created a class that extends InputStream so that I can keep count of the number of bytes being read and throw an exception if it exceeds a max limit that I define.

Here is my class:

    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.");
            }
        }
    }

This is coming from: Copy InputStream, abort operation if size exceeds limit , I am implementing a Jersey API that needs to fail if a user is uploading a file that is too large.

Here is my resource class:

    @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
        }
}

I wrapped LimitedSizeInputStream in my try resource so I think the stream should close properly. I'm just a bit confused as to whether the close is handled correctly or if I'm technically opening two input streams through LimitedSizeInputStream and file.getValueAs(InputStream.class) and only one is closing?

The try-with-resources only closes the declared resource. So will only close metadataStream .

You should implement the close method in LimitedSizeInputStream to close the original stream.

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

If LimitedSizeInputStream extends InputStream and wraps another stream, then @areus's solution is the best one.

An alternative approach would be to extend FilterInputStream , like this:

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.
}

Note that FilterInputStream provides default implementations of the API methods that may prove useful.

The javadoc provides details of what the default method implementations do.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM