Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Copy InputStream, abort operation if size exceeds limit

Tags:

I tried to copy an InputStream to a File, and abort the copy if the size of InputStream is greater than 1MB. In Java7, I wrote code as below:

public void copy(InputStream input, Path target) {
    OutputStream out = Files.newOutputStream(target,
            StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE);
    boolean isExceed = false;
    try {
        long nread = 0L;
        byte[] buf = new byte[BUFFER_SIZE];
        int n;
        while ((n = input.read(buf)) > 0) {
            out.write(buf, 0, n);
            nread += n;
            if (nread > 1024 * 1024) {// Exceed 1 MB
                isExceed = true;
                break;
            }
        }
    } catch (IOException ex) {
        throw ex;
    } finally {
        out.close();
        if (isExceed) {// Abort the copy
            Files.deleteIfExists(target);
            throw new IllegalArgumentException();
        }
    }}
  • First question: is there any better solution for it?
  • Second question: my other solution - Before the copy operation, I calculate the size of this InputStream. So I copy the InputStream to ByteArrayOutputStream then get size(). But the problem is InputStream may not markSupported(), so the InputStream cannot be reused in a copy file operation.
like image 462
卢声远 Shengyuan Lu Avatar asked Mar 16 '13 04:03

卢声远 Shengyuan Lu


People also ask

What happens if you don't close an InputStream?

The operating system will only allow a single process to open a certain number of files, and if you don't close your input streams, it might forbid the JVM from opening any more.

How does InputStream read () method work?

read() method reads the next byte of the data from the the input stream and returns int in the range of 0 to 255. If no byte is available because the end of the stream has been reached, the returned value is -1.

Does InputStream need to be closed?

You do need to close the input Stream, because the stream returned by the method you mention is actually FileInputStream or some other subclass of InputStream that holds a handle for a file. If you do not close this stream you have resource leakage.

How do I close an InputStream?

You close an InputStream by calling the InputStream close() method. Here is an example of opening an InputStream , reading all data from it, and then closing it: InputStream inputstream = new FileInputStream("c:\\data\\input-text. txt"); int data = inputstream.


2 Answers

My personal choice is an InputStream wrapper that counts bytes as it reads them:

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

}

I like this approach because it is transparent, it is re-usable with all input streams and it works well with other libraries. For example copying files up to 4KB with Apache Commons:

InputStream in = new LimitedSizeInputStream(new FileInputStream("from.txt"), 4096);
OutputStream out = new FileOutputStream("to.txt");
IOUtils.copy(in, out);

PS: The main difference of the implementation above with BoundedInputStream is that BoundedInputStream does not throw an exception when the limit is exceeded (it just closes the stream)

like image 87
idrosid Avatar answered Oct 23 '22 23:10

idrosid


There are following ready solutions for this:

  • ByteStreams.limit() from Guava
  • BoundedInputStream from Apache Commons
like image 38
husayt Avatar answered Oct 24 '22 01:10

husayt