Java使用Aspose Words合并rtf文件,内存溢出

您好:
问题:在使用com.aspose.words合并rtf文件的时候,总是产生内存溢出。
java.lang.OutOfMemoryError: Java heap space

环境及配置参数:jdk11 + spring boot 2.3.3 + aspose-words-21.5.0-jdk17.jar

合并的rtf文件为237个,合计大小为338m。使用的是tomcat部署的spring-boot项目,jvm初始内存
3.2G,最大内存4.8G。

核心代码:

Document first = new Document(baseFilePath);
int mode = ImportFormatMode.KEEP_SOURCE_FORMATTING;
for (String filePath : arrays)
{
    Document temp = new Document(filePath);
    first.appendDocument(temp, mode);
}
first.save(savePath);

想确认下以下问题:
1、内存溢出这个问题,是否是我们代码的问题?
2、一个rtf文件假如1m,不算太复杂,加载到内存需要多大的对象?
3、是否可以主动释放内存,该怎么做?
4、有更好的建议做rtf合并么?

感谢!

@imzdong 您的合并文档代码是正确的。 但您应该注意,在内存中构建文档模型需要比原始文档大小多几倍的内存。 请参阅我们的文档以获取更多信息:
https://docs.aspose.com/words/net/memory-requirements/
一旦文档超出范围,Aspose.Words 就会释放分配的内存。

使用最新版本的 Aspose.Words,您可以使用 Merger 类来合并文档。

String[] documents = new String[] {"in1.docx","in2.docx","in3.docx"};
Merger.merge("out.docx", documents, SaveFormat.DOCX, MergeFormatMode.KEEP_SOURCE_FORMATTING);

非常感谢你的帮助!

我继续测试这个code,测试数据一共是个文件,一个一个合并,发现合并后的大小和原文件合计的大小不符。

public static String mergeRtf(List<String> arrays, String savePath) throws Exception {
    String one = arrays.get(0);
    for (int i = 1; i < arrays.size(); i++) {
        String two = arrays.get(i);
        one = doMergeRtf(one, two, savePath + File.separator + "Merge_" +i + ".rtf");
    }
    return one;
}

private static String doMergeRtf(String org, String target, String savePath) throws Exception {
    int mode = ImportFormatMode.KEEP_SOURCE_FORMATTING;
    Document first = new Document(org);
    Document temp = new Document(target);
    first.appendDocument(temp, mode);
    first.save(savePath);
    return savePath;
}

发现合并后的rtf文件大小比原文件的大小增加的太多了,这个正常么?

源文件大小 合计也就9.9M
image.png (4.6 KB)

每两个合并后的大小增幅都不小,最终的大小是34.9m,增加了好几倍,这个正常么?
image.png (4.4 KB)

测试文件一共是10个文件

@imzdong 您能在这里附上您的源文件进行测试吗? 我们将检查它们并为您提供更多信息。 但是,是的,最终文档的大小可能会改变。 Aspose.Words 生成的 RTF 文档接近 MS Word 的 RTF,这可能会使文件的大小比原来简化的 RTF 更大。

好的,我提供我的测试文件。共计19个。总大小为3.27M。合并完后大小为19m左右。

test-data.zip (114.5 KB)

@imzdong 您可以通过指定 RtfSaveOptions.setExportCompactSize 属性来减小最终 RTF 大小:

RtfSaveOptions opt = new RtfSaveOptions();
opt.setExportCompactSize(true);

在本例中,最终文档大小为 9.5MB。

您的 RTF 文档似乎不是使用 MS Word 创建的,而是使用某些简化的 RTF 编辑器创建的。 如果您只是使用 MS Word 打开/保存 RTF 文档,它们的大小将增加大约 4 倍。

对的,我rtf文件是sas生成的。

我使用了

RtfSaveOptions rtfSaveOptions = new RtfSaveOptions();
rtfSaveOptions.setMemoryOptimization(true);
rtfSaveOptions.setExportCompactSize(true);

这两个参数。文件大小降了下来也是9.25m
还使用了rtfSaveOptions.setTempFolder(“temp”);这个参数。但这个参数我没感觉在合并中有什么作用。

感谢您的回答。
我现在的需求既想合并一定量的rtf,又想控制内存的使用。貌似不可行。
使用aspose,内存会在10·20倍之间。合并后生成文件的大小在3-4倍之间。
刚开始我以为我使用的问题,实际上是aspose为了更好保留样式而做出的用内存解决的方案吧。

@imzdong RtfSaveOptions.setTempFolder 不会影响输出文档大小以及 RtfSaveOptions.setMemoryOptimization。 这些选项仅影响 Aspose.Words 分配的用于处理文档的内存。 恐怕没有办法使用 Aspose.Words 生成更小的 RTF 文档。

@alexey.noskov. 好的,非常感谢

1 Like