英文:
When to close the InputStream?
问题
File file = new File("f:\041328370.pdf");
Anchor a;
try {
InputStream is = new FileInputStream(file);
StreamResource res = new StreamResource("10041328370.pdf", () -> is);
a = new Anchor(res, "点击这里下载");
a.getElement().setAttribute("download", "下载文件.pdf");
add(a);
// 请注意:避免在此处关闭 InputStream,否则当用户点击链接下载 PDF 文件时会导致 "Stream Closed" 错误。
} catch (IOException e) {
throw new RuntimeException(e.getMessage());
}
英文:
I am using Vaadin and I need to create a link to download a PDF file.
However, I need to close the InputStream. But if I close it when the user clicks to download the PDF file it is closed and throws an Exception. Where the correct place to close it?
File file = new File("f:\041328370.pdf");
Anchor a;
try{
InputStream is= new FileInputStream(file);
StreamResource res = new StreamResource("10041328370.pdf", () -> is );
a = new Anchor(res, "click here to download");
a.getElement().setAttribute("download", "downloaded-other-name.pdf");
add(a);
is.close(); //if close here, when the user to click in the anchor, we will get the error: Stream Closed.
} catch (IOException e) {
throw new RuntimeException(e.getMessage);
}
答案1
得分: 6
你不需要关闭InputStream。通过为StreamResource
提供一个InputStreamFactory
,将会调用您的工厂来创建一个新的输入流,并且会始终为您关闭它(参见com.vaadin.flow.server.StreamResource.Pipe#accept
使用try-with-resources)。
但问题在于,您提供了一个“常量”工厂,它总是返回相同的输入流。因此,第二次下载将在已关闭的输入流上失败。您实际上应该像一个真正的工厂一样实现工厂,并始终返回一个新的输入流。
例如:
StreamResource res = new StreamResource("10041328370.pdf", () ->
new FileInputStream(file));
英文:
You don't need to close the InputStream. Providing the StreamResource
an InputStreamFactory
will call your factory to create an fresh input stream and will always close it for you (see com.vaadin.flow.server.StreamResource.Pipe#accept
using try-with-resources).
But the problem here is, that you are providing a "constant" factory, that always returns the same IS. So the second download will now fail on the closed IS. You should actually implement the factory like a real factory and always return a new IS.
E.g.
StreamResource res = new StreamResource("10041328370.pdf", () ->
new FileInputStream(file));
答案2
得分: -3
你应该在 try-catch 语句块之外初始化 InputStream。流的范围仅限于 try 块内部,因此在需要关闭它的地方(在该块之外),由于它不再存在,所以关闭是不可能的。也许可以在初始化文件后再初始化它:
File file = new File("f:\041328370.pdf");
InputStream is = new FileInputStream(file);
Anchor a;
try {
StreamResource res = new StreamResource("10041328370.pdf", () -> is);
a = new Anchor(res, "点击这里下载");
a.getElement().setAttribute("download", "downloaded-other-name.pdf");
add(a);
is.close(); // 如果在这里关闭,当用户点击链接时,会出现错误:流已关闭。
} catch (IOException e) {
throw new RuntimeException(e.getMessage);
}
也许将 StreamResource 的位置也移动一下会更好。
编辑:回答你的问题,与其关注在哪里关闭流,不如关注在哪里打开它。在不需要输入的地方关闭它。
英文:
You should probably initialize the InputStream outside of your try catch statement. The scope of the stream is solely inside the try block, so closing it where you need to (outside of that block) is impossible since it no longer exists. Initialize it perhaps after you initialize your file:
File file = new File("f:\041328370.pdf");
InputStream is= new FileInputStream(file);
Anchor a;
try{
StreamResource res = new StreamResource("10041328370.pdf", () -> is );
a = new Anchor(res, "click here to download");
a.getElement().setAttribute("download", "downloaded-other-name.pdf");
add(a);
is.close(); //if close here, when the user to click in the anchor, we will get the error: Stream Closed.
} catch (IOException e) {
throw new RuntimeException(e.getMessage);
}
It may be good to move the StreamResource as well.
EDIT: To answer your question, it's less about where you close the stream and more about where you open it. Close it wherever you're done taking input.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论