java - 替换为大文件 java 堆空间内存不足

标签 java string xml-parsing

我有一个 250mb 的大 xml 文档,其中一个标签包含我需要处理的另一个 xml。

但问题是,这个xml被CDATA包裹着如果我尝试做 replace/replaceAll

String xml= fileContent.replace("<![CDATA[", "  ");
String replace = xml.replace("]]>", " ");

我开始了

java.lang.OutOfMemoryError: Java heap space

结构的简单示例。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<a>
    <b>
        <c>
            <![CDATA[<?xml version="1.0" encoding="UTF-8" standalone="yes"?><bigXML>]]>
        </c>
    </b>
</a>

即使使用像 VDT 这样的 XML 解析器或SAX它没有帮助,因为我仍然需要删除 <![CDATA[我们里面的内容是文件的最大部分。

分配更多内存堆不是一个选项,因为它在我没有任何 JVM 控制的机器上运行。

安妮知道如何从 c 中提取 xml标记并摘自 <![CDATA[

更新

我尝试使用 Streams 进行修改,如下所示,但我仍然有 outOfMemories .

知道如何改进代码以避免错误吗?

private void readUpdateAndWrite(
    Reader reader,
    String absolutePath
) {
    // Write the content in file
    try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(absolutePath))) {
        // Read the content from file
        try (BufferedReader bufferedReader = new BufferedReader(reader)) {
            String line = bufferedReader.readLine();
            while (line != null) {
                String replace = line
                    .replace("<![CDATA[", " ")
                    .replace("]]>", " ");
                bufferedWriter.write(replace);
                line = bufferedReader.readLine();
            }
        } catch (IOException e) {
            logger.error("Error writing in file. Caused by {}", getStackTrace(e));
        }
    } catch (IOException e) {
        logger.error("Error reading in file. Caused by {}", getStackTrace(e));
    }
}

我发现了我的问题。 <![CDATA[的内容是一个 256mb 的字符串行,所以我无法在该行中进行任何替换,或者我得到 outOfMemory .

如何将 256mb 的字符串分成新行。我尝试创建另一个 InputStream通过大量的字符串,但不起作用。

我猜是因为是嵌入式 XML,我们不能有多行。

最佳答案

您遇到的问题是您没有足够的内存来分配如此大的字符串的副本。调用 String.replace将使用替换部分的副本创建一个新字符串。如果大多数文本都在这些标签内并且 fileContent是 250MB 那么你的双 replace将在短时间内连续分配 2 x 250MB 字符串。

分配更多内存可以轻松解决此问题,但如果您说无法执行此操作,请尝试使用不同的方法来加载字符串并扫描内容。一种方法是扫描文件标记位置并将匹配的部分保存到另一个文件中。例如

String cdata = "<![CDATA[";
int start = fileContent.indexOf(cdata);
int end   = fileContent.lastIndexOf("]]>");

将剥离的部分写出到另一个文件。这不会在内存中实例化 250MB 字符串的第二个副本,并且应该为您留下包含 <c> 内的部分的文件。正在进行处理的标签。

try(var os = Files.newBufferedWriter(bigxml)) {
    os.write(fileContent, start+cdata.length(), end-start-cdata.length());
}

如果fileContent中有多个开始/结束标记,这并不理想,并且可能会失败.

关于java - 替换为大文件 java 堆空间内存不足,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69786122/

相关文章:

powershell - 带#sign 的成员(member)

java - Android RSS 源

java.lang.ClassNotFoundException : com. google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier$Builder

java - 而不是多个 if 语句 Java date

python - 列表中每个单词的平均字符数

string - Haskell 中任意长度的多个分隔符分割字符串

Java 编译器不同意泛型方法调用的安全性

C++ std::string 与 !=、< 和 > 的用法

ios - 如何在 iOS RSS 应用程序中显示解析后的 XML 中的图像?

java - 尝试使用 SAXParser 解析 Android 应用程序中的 XML