Java文件下载挂起 [英] Java file download hangs

查看:383
本文介绍了Java文件下载挂起的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个用于下载文件的Web界面。当请求进入时,我的glassfish服务器从Web服务流式传输文件,然后将内容写入输出流。我的代码工作正常,除非文件大小变得非常大(如超过200 MB),它挂起显示0%已下载到浏览器中,文件永远不会下载。

I have a web interface which is used to download a file. When the request comes in, my glassfish server streams the file from a web service and then writes the content to the outputstream. My code works fine except when the file size becomes very large (like more than 200 MB), it hangs showing 0% donwloaded in the browser and the file is never downloaded.

当我在while循环中移动flush()方法时,它也适用于大文件。我不确定在循环中放置flush()是否有问题。不知道这件事实际上是如何运作的。我的代码如下:

When I move flush() method inside the while loop it works fine for large files as well. I am not sure if putting flush() in a loop is a problem. Not sure how this thing actually works. My code is as follows :

HttpURLConnection conn = (HttpURLConnection) downloadUri.toURL().openConnection();
        conn.setDoOutput(true);
        conn.setRequestMethod("GET");
        conn.setRequestProperty("Content-Type", "application/pdf");
        if (conn.getResponseCode() == 200) {
            ServletOutputStream output;
            try (InputStream inputStream = conn.getInputStream()) {
                HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();
                response.setContentType("application/octet-stream");
                response.setHeader("Content-Length", conn.getHeaderField("Content-Length"));
                response.setHeader("Content-Disposition", "attachment; filename=\"" + abbr + ".pdf\"");
                output = response.getOutputStream();
                byte[] buffer = new byte[1024];
                int bytesRead;                    
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    output.write(buffer, 0, bytesRead);                        
                }
            }                 
            output.flush();
            output.close();

有什么想法吗?感谢您查看此内容。

Any thoughts?. Thank you for looking into this.

推荐答案

flush()方法指示流实际沿流管道发送输出。

The flush() method instructs the stream to actually send the output down the stream pipe.

出于各种性能原因,各种流实现可以缓存输出而不是立即写入基础流。

Various stream implementation can, for various performance reasons, cache the output and not write to the underlying stream right away.

例如,从性能的角度来看,在磁盘上保存IO操作是很昂贵的。

For example to save IO operations on disk which are expensive from a performance point of view.

刷新流没有问题,如果不是为了表演,在这种情况下,你想要的是:流似乎被卡住,直到你冲洗它,所以你希望它实际上把东西发送到客户端。

There is no problem in flushing a stream, if not for performances, which in this case is what you want : the stream seems to be stuck until you flush it, so you want it to actually send stuff to the client.

也许你可以玩大小超过1024的缓冲区,看看哪个更合适。

Maybe you can play with the size of your buffer, with something bigger than 1024, to see what fits better.

编辑:

在循环中刷新循环或不循环的问题是相对不相关的。

The problem of flushing in a loop or not in a loop is relatively not relevant.

你可以随时调用flush,因为它会调用unde操作系统流,无论是性能影响还是不影响取决于具体情况。

You can call flush whenever you want, as said it will call the underlying OS stream, whether this is a performance hit or no depends on the situation.

例如,你可以估计流中缓冲文件的200MB内存比IO操作更重要,也是性能方面的。

For example, you could value the 200MB of ram in which the stream is buffering the file more important, also performance-wise, than the IO operation.

或者更简单地看待用户体验看到文件实际下载比您可能遇到的最终性能影响更重要,如果您设法测量它。

Or much more simply value the user experience of seeing the file actually downloading more important than the eventual performance hit you might maybe experience, if you manage to measure it.

如上所述,缓冲区越大,循环问题越少。假设,作为一个极端的例子,你的缓冲区是100兆字节,那么一个80兆字节的文件将只获得一个刷新,它将在请求结束时得到它。

As said, the larger is your buffer, the less the problem of the loop is. Suppose, as an extreme example, your buffer is 100 megabyte, then an 80 megabyte file will get only one flush, which it would get anyway at the end of the request.

拥有1k的缓冲区可能太小,4k更好,16k就好了,这是IO调用和RAM消耗之间的权衡。

Having 1k of buffer is probably too small, 4k better, 16k fine, it's a tradeoff between IO calls and RAM consumption.

流应该自己做正确的工作,但是如果你看到一个200MB的文件被完全缓存,除非你调用flush,那么显然这个流可能会优化性能但是会给用户带来不好的体验,所以显然你需要它在循环中。

The stream should do it's proper work itself, if however you're seeing that a 200MB file get's fully cached unless you call flush, then obviously the stream is probably optimizing performances but giving a bad user experience, so obviously you need it in the loop.

这篇关于Java文件下载挂起的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆