编辑:
获取目录。现在还有另一个问题:
存储中的文件以其DB id作为前缀存储 他们的文件名。当然我不希望用户看到这些。
有没有办法将response.redirect和标题设置结合起来 文件名和大小?
最好的,
A
你好,
新方法:
是否可以按顺序在tomcat中创建类似IIS的虚拟目录 避免流式传输,只使用标题重定向?我一起玩 背景但却无法实现......
任何想法?
thx
A
嗨%,
我正面临着Java堆空间的有线问题 把我带到绳索上。
简短版本是:
我编写了一个需要处理的ContentManagementSystem 巨大的文件(> 600mb)也是。 Tomcat堆设置:
-Xmx700m -Xms400m
问题是,上传大文件的确很有效 慢。下载文件会导致java堆空间异常。
尝试下载370mb文件会使tomcat跳转到500mb堆 (应该没问题)并以Java堆空间异常结束。
我不明白,为什么上传工作和下载不? 这是我的下载代码:
byte[] byt = new byte[1024*1024*2];
response.setHeader("Content-Disposition", "attachment;filename=\"" + fileName + "\"");
FileInputStream fis = null;
OutputStream os = null;
fis = new FileInputStream(new File(filePath));
os = response.getOutputStream();
BufferedInputStream buffRead = new BufferedInputStream(fis);
while((read = buffRead.read(byt))>0)
{
os.write(byt,0,read);
os.flush();
}
buffRead.close();
os.close();
如果我说得对,那么缓冲读者应该照顾好任何一个 记忆问题,对吧?
任何帮助都会受到高度赞赏,因为我没有想法
致以最诚挚的问候,
w ^
答案 0 :(得分:5)
如果我说得对,那么缓冲 读者应该照顾好任何记忆 问题,对吧?
不,这与内存问题无关,因为您已经在使用缓冲区来读取文件,所以实际上没有必要。你的问题在于写作,而不是阅读。
我无法看到您的代码出现任何问题。看起来Tomcat正在缓冲整个响应而不是流式传输。我不确定是什么原因引起的。
response.getBufferSize()
返回什么?你应该尝试将response.setContentLength()
设置为文件的大小;我依稀记得在某些情况下,一个Web容器会缓冲整个响应以确定内容长度,所以也许这就是正在发生的事情。最好这样做是因为它使客户能够显示下载大小并为下载提供ETA。
答案 1 :(得分:1)
尝试使用ServletResponse的setBufferSize和flushBuffer方法。
答案 2 :(得分:1)
您最好使用 java.nio ,这样您就可以部分阅读资源并释放已经过流的资源!
否则,尽管您已经对JVM环境进行了设置,但最终会出现内存问题。
答案 3 :(得分:1)
我的建议:
Quick-n-easy: 使用更小的阵列!是的,它循环更多,但这不会是一个问题。 5千字节就好了。你会在几分钟内知道这是否适合你。
byte[] byt = new byte[1024*5];
稍微难点: 如果您有权访问sendfile(例如在Tomcat中使用Http11NioProtocol
- documentation here),那么请使用它
再努力一点: 将代码切换到Java NIO的FileChannel。我有非常非常相似的代码运行在同样大的文件上,有数百个并发连接和类似的内存设置没有问题。在这些情况下,NIO比普通的旧Java流更快。它使用DMA(Direct Memory Access)的魔力,允许数据从磁盘进入NIC而无需通过RAM或CPU。这是我自己的代码库的代码片段...我已经扯掉了许多来展示基础知识。 FileChannel.transferTo()不保证每个字节发送一次,所以它就在这个循环中。
WritableByteChannel destination = Channels.newChannel(response.getOutputStream());
FileChannel source = file.getFileInputStream().getChannel();
while (total < length) {
long sent = source.transferTo(start + total, length - total, destination);
total += sent;
}
答案 4 :(得分:1)
以下代码能够将数据流传输到客户端,只分配一个小缓冲区(BUFFER_SIZE,这是一个软点,因为您可能需要调整它):
private static final int OUTPUT_SIZE = 1024 * 1024 * 50; // 50 Mb
private static final int BUFFER_SIZE = 4096;
@Override
protected void doGet(HttpServletRequest request,HttpServletResponse response)
throws ServletException, IOException {
String fileName = "42.txt";
// build response headers
response.setStatus(200);
response.setContentLength(OUTPUT_SIZE);
response.setContentType("text/plain");
response.setHeader("Content-Disposition",
"attachment;filename=\"" + fileName + "\"");
response.flushBuffer(); // write HTTP headers to the client
// streaming result
InputStream fileInputStream = new InputStream() { // fake input stream
int i = 0;
@Override
public int read() throws IOException {
if (i++ < OUTPUT_SIZE) {
return 42;
} else {
return -1;
}
}
};
ReadableByteChannel input = Channels.newChannel(fileInputStream);
WritableByteChannel output = Channels.newChannel(
response.getOutputStream());
ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
while (input.read(buffer) != -1) {
buffer.flip();
output.write(buffer);
buffer.clear();
}
input.close();
output.close();
}
答案 5 :(得分:1)
您是否需要使用Tomcat提供文件?对于这种任务,我们使用了单独的下载机制。我们链接了Apache - &gt; Tomcat - &gt;存储然后添加重写规则以供下载。然后您只需绕过Tomcat,Apache就会将文件提供给客户端(Apache-&gt;存储)。但是,只有在文件存储为文件时才有效。如果从DB或其他类型的非文件存储中读取此解决方案,则无法成功使用。整个方案是您为文件生成下载链接,例如domain / binaries / xyz ...并使用Apache mod_rewrite为域/文件编写重定向规则。
答案 6 :(得分:0)
您是否在应用程序中有任何过滤器,或者您是否使用了tcnative库?您可以尝试使用jvisualvm进行配置文件吗?
编辑:小注释:请注意,如果不清理fileName,则setHeader中存在HTTP响应拆分攻击的可能性。
答案 7 :(得分:0)
为什么不使用tomcat自己的FileServlet?
它肯定会比你想象的更好地发布文件。
答案 8 :(得分:-1)
2 MB的缓冲区方式太大了!一些k应该足够了。兆字节大小的对象是垃圾收集器的真正问题,因为它们通常需要与“普通”对象分开处理(正常==比堆生成小得多)。要优化I / O,您的缓冲区只需要略大于I / O缓冲区大小,即至少与磁盘块或网络包一样大。