有没有更好的方法将文件的完整内容写入 OutputStream?

29
当我想将文件的全部内容写入OutputStream时,通常会分配一个缓冲区作为byte[],然后使用for循环从文件的InputStreamread数据到缓冲区并将缓冲区内容写入OutputStream,直到InputStream没有更多可用字节。
这种方法对我来说似乎有些笨拙。有更好的方法吗?
此外,我总是不确定缓冲区大小。通常,我分配1024个字节,因为这感觉很好。是否有更好的方法确定合理的缓冲区大小?
在我的当前情况下,我想将文件的全部内容复制到写入HTTP响应内容的输出流中。因此,这不是有关如何在文件系统上复制文件的问题。
3个回答

43

对于Java 1.7+,您可以使用Files.copy(Path, OutputStream)方法进行复制。

HttpServletResponse response = // ...
File toBeCopied = // ...

try (OutputStream out = response.getOutputStream()) {
    Path path = toBeCopied.toPath();
    Files.copy(path, out);
    out.flush();
} catch (IOException e) {
    // handle exception
}

请注意,由于你正在处理HttpServletResponse,因此设置正确的响应头也是一个好主意。在将实际文件数据复制到响应之前,请添加以下行:

请注意,由于您正在处理HttpServletResponse,因此设置正确的响应头也是个好主意。在将实际文件数据复制到响应之前,请添加以下行:

String mimeType = URLConnection.guessContentTypeFromName(toBeCopied.getName());
String contentDisposition = String.format("attachment; filename=%s", toBeCopied.getName());
int fileSize = Long.valueOf(toBeCopied.length()).intValue();

response.setContentType(mimeType);
response.setHeader("Content-Disposition", contentDisposition);
response.setContentLength(fileSize);

请注意,传递给内容分发的文件名编码非常重要,请参见这个问题


我的单元测试如何验证写入OutputStream的内容?ServletOutputStream mockOutput = mock(ServletOutputStream.class); 当(response.getOutputStream()).thenReturn(mockOutput); - Philip Rego

30

Apache Commons-IO:

IOUtils.copy(fileInputStream,outputStream);

JDK NIO

new FileInputStream(file).getChannel().transferTo(otherChannel);

哇,我在Bozho的回答中简短地评论了Commons-IO。但是,这个通道解决方案正是我一直在寻找的。非常感谢,所有的NIO通道都错过了我,因为在NIO出现之前我已经学习了Java IO。顺便说一下:9分钟!那几乎就像闪电一样快。 - Madoc
2
不要忘记关闭 FileInputStream - yegor256

12

使用commons-io,您可以得到一行解决方案:

IOUtils.copy(yourFileInputStream, outputStream);

请注意,您需要手动关闭流(或使用IOUtils.closeQuitely(..)


这也是我的建议。虽然它的功能是一样的。 - rfeak
看起来非常不错。但对于这个简单的任务来说,我觉得包含另一个库有点过度了。当然,如果有更多的理由需要包含Commons-IO,那么这将是首选的解决方案。 - Madoc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接