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();
}
}}
ByteArrayOutputStream
then get size()
. But the problem is InputStream may not markSupported()
, so the InputStream cannot be reused in a copy file operation.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.
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.
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.
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.
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)
There are following ready solutions for this:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With