首页 > 解决方案 > StringBuilder.append 内存不足

问题描述

我正在使用 StringBuilder.append() 来解析和处理文件,如下所示:

        StringBuilder csvString = new StringBuilder();

        bufferedReader.lines().filter(line -> !line.startsWith(HASH) && !line.isEmpty()).map(line -> line.trim())
                .forEachOrdered(line -> csvString.append(line).append(System.lineSeparator()));

        int startOfFileTagIndex = csvString.indexOf(START_OF_FILE_TAG);

        int startOfFieldsTagIndex = csvString.indexOf(START_OF_FIELDS_TAG, startOfFileTagIndex);
        int endOfFieldsTagIndex = csvString.indexOf(END_OF_FIELDS_TAG, startOfFieldsTagIndex);

        int startOfDataTagIndex = csvString.indexOf(START_OF_DATA_TAG, endOfFieldsTagIndex);
        int endOfDataTagIndex = csvString.indexOf(END_OF_DATA_TAG, startOfDataTagIndex);

        int endOfFileTagIndex = csvString.indexOf(END_OF_FILE_TAG, endOfDataTagIndex);

        int timeStartedIndex = csvString.indexOf("TIMESTARTED", endOfFieldsTagIndex);
        int dataRecordsIndex = csvString.indexOf("DATARECORDS", endOfDataTagIndex);
        int timeFinishedIndex = csvString.indexOf("TIMEFINISHED", endOfDataTagIndex);

        if (startOfFileTagIndex != 0 || startOfFieldsTagIndex == -1 || endOfFieldsTagIndex == -1
                || startOfDataTagIndex == -1 || endOfDataTagIndex == -1 || endOfFileTagIndex == -1) {

            log.error("not in correct format");

            throw new Exception("not in correct format.");
        }

问题是当文件很大时,我得到一个内存不足的异常。你能帮我转换我的代码以避免大文件的异常吗?

编辑:据我所知,将一个大文件充电到一个字符串 Builder 不是一个好主意,也不会工作。所以问题是Java中的哪个结构更适合用来解析我的大文件,删除一些行,找到一些行的索引并将文件分成几部分(在哪里存储这些部分可能很大)根据找到索引然后最后创建一个输出文件?

标签: javafileout-of-memorystringbuilder

解决方案


OOM 似乎是由于您将所有行都存储在StringBuilder. 当文件行数过多时,会占用大量内存,可能导致OOM。

避免这种情况的策略取决于您对附加字符串所做的操作。正如我在您的代码中看到的,您只是在尝试验证输入文件的结构。在这种情况下,您不需要将所有行存储在一个StringBuilder实例中。反而,

  1. 有多个ints 来保存您感兴趣的每个索引,(或有一个ints 数组)
  2. 不要将行添加到 中StringBuilder,而是检测您正在寻找的“标签”或“索引”的存在并将其保存在其指定的int变量中。
  3. 最后,您已经在做的检查可能需要进行更改以测试不是-1相对于其他指数而是相对于其他指数。(您当前正在使用indexOf()调用中的开始索引来实现这一点。)
  4. 如果标签存在跨行的风险,那么您可能无法使用流,但必须使用一个简单的for循环来保存一些先前的行,附加它们并检查。(只有一个想法;您可能有更好的想法。)

推荐阅读