【问题标题】:Handle large file (>2GB) in the ByteArrayInputStream处理 ByteArrayInputStream 中的大文件 (>2GB)
【发布时间】:2023-03-30 07:32:01
【问题描述】:

我从其他方法获得了一个 ByteArrayInputStream 格式的非常大的文件(>2.5GB)数据。我必须将此数据以 InputStream 格式传递给另一个方法。我编写了以下代码,对于较小的文件执行良好,但对于超过 2GB 大小的大文件,它会失败。

ByteArrayInputStream bais = null;
bais = method_Returns_FIle_In_ByteArrayInputStream_Format();
InputStream is = bais;
method_Where_To_send_Data_In_InputStream_Format(is);

但我的代码本身在第二行中断,出现以下错误:

java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Arrays.java:3236)
    at java.io.ByteArrayOutputStream.grow(ByteArrayOutputStream.java:118)
    at java.io.ByteArrayOutputStream.ensureCapacity(ByteArrayOutputStream.java:93)
    at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:153)

已经尝试增加 Java 堆空间大小(-Xms 和 -Xmx)。

欢迎提出任何建议。

【问题讨论】:

  • 为什么要将整个文件加载到内存中?是否可以选择只使用FileInputStream
  • 找到一个解决方案,这样您就不必在处理内存之前将所有内容加载到内存中(例如,使用来自磁盘或网络的不同类型的输入流)。
  • @Progman 我看不到如何在这里使用 FileInputStream?目前是 Java 新手。
  • @MarkRotteveel 我会尝试找到与这些相关的示例。
  • @suchit A FileInputStream 让您无需将文件完全读入内存即可访问文件。由于它是从 InputStream 扩展而来的,因此您可以在 method_Where_To_send_Data_In_InputStream_Format() 方法中使用它。

标签: java out-of-memory inputstream bytearrayoutputstream bytearrayinputstream


【解决方案1】:

我从其他方法获得了一个 ByteArrayInputStream 格式的非常大的文件(>2.5GB)数据。

战争以另一种方式失败了。如果你不能改变“另一种方法”,那你就不走运了。在这里您绝对无能为力。 ByteArrayInputStream根据定义是完全在内存中的事情,如果 2.5GB 的数据包含该流的全部内容,那么 BAIS 至少需要 2.5GB 的内存。 您无能为力

修复方法是使用该方法并修复它。它绝对没有业务以 BAIS 形式发送。 InputStream 的“要点”就在名称中:流式传输该数据。

如果您无法更改它,而 64 位 VM 上的 -Xmx8g 无法修复它,则没有什么可做的。

【讨论】:

    【解决方案2】:

    您不应该尝试加载整个文件然后从内存中读取它。

    try (InputStream is = method_Returns_FIle_In_InputStream_Format()) {
        method_Where_To_send_Data_In_InputStream_Format(is);
    }
    

    以上使用 try-with-resources 自动关闭 is,即使出现异常、中断或返回。

    文件读取方法可以做

    Path path = Paths.get("phantasies.log");
    return Files.newInputStream(path);
    

    当想要对文件输入进行一些额外处理时,可以将 InputStream 包装在您的自定义子 FilterInputStream 中。

    这也表明,针对接口 (InputStream) 而不是实际实现 (ByteArrayInputStream) 进行编程更好。

    如果ByteArrayInputStream 源于收集OutputStream,则应该使用java 的管道I/O:PipedInputStreamPipedOutputStream - 加上一个额外的Thread

    也可以使用压缩来减小内存大小,GZipInputStream/GZipOutputStream

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-10-19
      • 2014-05-28
      • 1970-01-01
      • 2013-06-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多