简体   繁体   English

Java:如何计算从 InputStream 读取的字节数而不分配之前的全部内存

[英]Java: How to count read bytes from InputStream without allocating the full memory before

I have a Java-backend where user can upload files to it.我有一个 Java 后端,用户可以在其中上传文件。 I want to limit these uploaded files to a max size and want to check the amount of uploaded bytes while the upload happens and break the transmission as soon as the limit is reached.我想将这些上传的文件限制为最大大小,并希望在上传发生时检查上传的字节数,并在达到限制后立即中断传输。

Currently I am using InputStream.available() before allocation for determination of estimated size, but that seems to be seen as unreliable.目前我在分配之前使用 InputStream.available() 来确定估计大小,但这似乎被视为不可靠。

Any suggestions?有什么建议吗?

You can use Guava's CountingInputstream or Apache IO's CountingInputStream when you want to know how many bytes have been read.当您想知道读取了多少字节时,您可以使用Guava 的 CountingInputstreamApache IO 的 CountingInputStream

On the other hand when you want to stop the upload immediatly when reaching some limit then just count while reading chunks of bytes and close the stream when the limit has been exceeded.另一方面,当您想在达到某个限制时立即停止上传时,只需在读取字节块时进行计数,并在超过限制时关闭流。

int count = 1;
InputStream stream;
if (stream.available() < 3) {
count++;
}
Result:
[0][1]{2][3] 
 1  1  1  1

You don't have to 'allocat[e] the full memory before'.您不必“之前分配[e] 全部内存”。 Just use a normally sized buffer, say 8k, and perform the normal copy loop, tallying the total transferred.只需使用一个正常大小的缓冲区,比如 8k,并执行正常的复制循环,计算传输的总数。 If it exceeds the quota, stop, and destroy the output file.如果超过配额,则停止并销毁输出文件。

If you're using a servlet and a multipart request you can do this:如果您使用 servlet 和多部分请求,您可以这样做:

public void doPost( final HttpServletRequest request, final HttpServletResponse response )
    throws ServletException, IOException {
  String contentLength = request.getHeader("Content-Length");
  if (contentLength != null && maxRequestSize > 0 && 
           Integer.parseInt(contentLength) > maxRequestSize) {
     throw new MyFileUploadException("Multipart request is larger than allowed size");
  }
}

My solution looks like this:我的解决方案如下所示:

public static final byte[] readBytes (InputStream in, int maxBytes)
throws IOException {
    byte[] result               = new byte[maxBytes];
    int bytesRead               = in.read (result);
    if (bytesRead > maxBytes) {         
        throw new IOException   ("Reached max bytes (" + maxBytes + ")");
    }       
    if (bytesRead < 0) {            
        result                  = new byte[0];
    }
    else {
        byte[] tmp              = new byte[bytesRead];
        System.arraycopy        (result, 0, tmp, 0, bytesRead);
        result                  = tmp;
    }       
    return result;
}

EDIT: New variant编辑:新变种

public static final byte[] readBytes (InputStream in, int bufferSize, int maxBytes)
throws IOException {

    ByteArrayOutputStream out       = new ByteArrayOutputStream();
    byte[] buffer                   = new byte[bufferSize];

    int bytesRead                   = in.read (buffer);
    out.write                       (buffer, 0, bytesRead);

    while (bytesRead >= 0) {

        if (maxBytes > 0 && out.size() > maxBytes) {

            String message          = "Reached max bytes (" + maxBytes + ")";
            log.trace               (message);
            throw new IOException   (message);
        }

        bytesRead                   = in.read (buffer);

        if (bytesRead < 0)
            break;

        out.write                   (buffer, 0, bytesRead);
    }

    return out.toByteArray();
}

All method implementations of read return the number of bytes read. read 的所有方法实现都返回读取的字节数。 So you can initiate a counter and increment it appropriately with each read to see how many bytes you've reads so far.因此,您可以启动一个计数器并在每次读取时适当地增加它,以查看到目前为止您已读取了多少字节。 Method available() allows you to see how many bytes are available for reading at the buffer at the moment and it has no relation to the total size of the file.方法 available() 允许您查看此时缓冲区中有多少字节可供读取,它与文件的总大小无关。 this method could be very useful though to optimize your reading so each time you can request to read the chunk that is readily available and avoid blocking.这种方法对于优化您的阅读非常有用,因此每次您都可以请求读取随时可用的块并避免阻塞。 Also in your case you can predict before reading if the amount of bytes that you will have after the upcoming reading will exceed your limit and thus you can cancel it even before you read the next chunk同样在您的情况下,您可以在阅读之前预测下一次阅读后您将拥有的字节数是否会超过您的限制,因此您甚至可以在阅读下一个块之前取消它

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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