我在StackOverflow上看到一些相互矛盾的帖子,我想得到明确的答案。
我开始假设使用Java InputStream允许我从文件中流出字节,从而节省内存,因为我不必立即使用整个文件。这正是我在这里读到的:
将所有字节加载到内存不是一个好习惯。考虑返回文件并打开输入流来读取它,这样在处理大文件时应用程序不会崩溃。 - andrucz
Download file to stream instead of File
但后来我用一个InputStream来读取一个非常大的Microsoft Excel文件(使用Apache POI库),我遇到了这个错误:
java.lang.outofmemory exception while reading excel file (xlsx) using POI
我收到了OutOfMemory错误。
这一点重要的建议救了我:
有一点不同的是,在打开文件时会有所不同。如果你有一个文件,那么传递它!使用InputStream需要将所有内容缓冲到内存中,从而占用空间。既然你不需要做那个缓冲,那就不要!
我摆脱了InputStream,只使用了一个裸java.io.File,然后OutOfMemory错误就消失了。
因此,当涉及内存使用时,使用java.io.File比InputSteam更好吗?这没有任何意义。
真正的答案是什么?
答案 0 :(得分:6)
所以你说
InputStream
通常有帮助吗?
这完全取决于应用程序(或库)>>如何使用<< InputStream
使用什么样的后续代码?你能提供一个内存高效Java的例子吗?
例如:
// Efficient use of memory
try (InputStream is = new FileInputStream(largeFileName);
BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
String line;
while ((line = br.readLine()) != null) {
// process one line
}
}
// Inefficient use of memory
try (InputStream is = new FileInputStream(largeFileName);
BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) {
sb.append(line).append("\n");
}
String everything = sb.toString();
// process the entire string
}
// Very inefficient use of memory
try (InputStream is = new FileInputStream(largeFileName);
BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
String everything = "";
while ((line = br.readLine()) != null) {
everything += line + "\n";
}
// process the entire string
}
(请注意,有更有效的方法将文件读入内存。以上示例纯粹是为了说明原则。)
这里的一般原则是:
您链接到上面的帖子:
第一个并不是关于内存效率。相反,它正在讨论AWS客户端库的限制。显然,API并没有提供一种在阅读时流式传输对象的简便方法。您必须将对象保存到文件,然后将该文件作为流打开。是否内存有效取决于应用程序对进行的操作;见上文。
第二个特定于POI API的。显然,如果您使用流,POI库本身正在将流内容读入内存。这将是该特定库的实现限制。