Java文件下载挂起

vin*_*nay 4 java outputstream flush

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

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

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();
Run Code Online (Sandbox Code Playgroud)

有什么想法吗?.感谢您对此进行调查.

Sim*_*nni 5

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

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

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

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

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

编辑:

在循环中冲洗或不在循环中冲洗的问题相对不相关.

您可以随时调用flush,因为它将调用底层操作系统流,无论这是性能影响还是不依赖于情况.

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

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

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

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

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

  • 因为您可能会强制网络层比其他情况更频繁地发送数据. (2认同)