问题
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?
回答1:
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();
}
回答2:
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.
来源:https://stackoverflow.com/questions/61738574/am-i-closing-my-input-stream-correctly-in-java