Java 内存不足,无法处理大型文本文件并将其写回xml

Java 内存不足,无法处理大型文本文件并将其写回xml,java,xml,Java,Xml,我是java编程新手,现在在处理大型文本文件方面遇到了问题。我正在编写代码来处理整个文件的字符串,将其解析为一个类,然后将其转换为xml。挑战在于我只能处理少于70K行的输出;如果我的内存超过800K,它将抛出一个错误“java.lang.OutOfMemoryError:java堆空间”。这是我的示例文件和代码 示例文件1 H|20090908| D|ABASTECEDORA NAVAL Y INDUSTRIAL, S.A. ,N|10 |9|4PANAMA |9|8

我是java编程新手,现在在处理大型文本文件方面遇到了问题。我正在编写代码来处理整个文件的字符串,将其解析为一个类,然后将其转换为xml。挑战在于我只能处理少于70K行的输出;如果我的内存超过800K,它将抛出一个错误“java.lang.OutOfMemoryError:java堆空间”。这是我的示例文件和代码

示例文件1

H|20090908|
D|ABASTECEDORA NAVAL Y INDUSTRIAL, S.A. ,N|10          |9|4PANAMA     |9|8  |        |                                                                                                                            |1|20090908|AMLA    |
D|ABDELNUR, NURY DE JESUS ,NULL           |15          |9|0PANAMA     |9|8  |        |                                                                                                                        |1|20090908|AMLA    |
D|ACECHILLY ,NULL                         |22          |9|0UNKNOWN    |9|8  |        |                                                                                                                        |1|20090908|AMLA    |
D|ACEFROSTY ,NULL                         |24          |9|0UNKNOWN    |9|8  |        |                                                                                                                        |1|20090908|AMLA    |
D|ACEFROSTY SHIPPING CO., LTD. ,NULL      |25          |9|0MALTA      |9|8  |        |                                                                                                                        |1|20090908|AMLA    |
T|0000013413|
下面是解析器类

import java.text.SimpleDateFormat;



public class WatchlistParser {

public Object receiveExternal(Object callback) {
    Object result = null;

    try {
        result = this.process("external_watchlist", callback);
    } catch (Exception e) {
        System.out.println(e.getMessage());
    }
    return result;
}

public Object receiveInternal(Object callback) {
    Object result = null;

    try {
        result = this.process("internal_watchlist", callback);
    } catch (Exception e) {
        System.out.println(e.getMessage());
    }
    return result;

}

public Object process(String filename, Object data) {
    java.util.Scanner scanner = new java.util.Scanner(data.toString());


    java.util.List<WatchlistEntryObject> list = new java.util.Vector<WatchlistEntryObject>();
    int entryCount = 1;

    String prefix="113";
    if (filename.equalsIgnoreCase("internal_watchlist")) {
        prefix = "113INT";
    }
    if (filename.equalsIgnoreCase("external_watchlist")) {
        prefix = "113EXT";
    }
    //         
    // read all watchlist entry and store it into a list
    SimpleDateFormat dateformatYYYYMMDD = new SimpleDateFormat("yyyyMMdd");
    while (scanner.hasNext()) {
        String line = scanner.nextLine();
        // Get data lines
        if (line.startsWith("D")) {
            // System.out.println("-"+line);
            // parse the data line

            line = line.replace("&", "&amp;");
            line = line.replace("'", "''");
            line = line.replace(">", "&gt;");
            line = line.replace("<", "&lt;");
            String fields[] = line.split("\\|");
            // do validation
            // field.size must 4

            if (fields.length == 12) {
                // do work
                WatchlistEntryObject wo = new WatchlistEntryObject();
                wo.setName(fields[1].trim());
                wo.setId(fields[2].trim());
                wo.setIdType(fields[3].trim());
                wo.setAltID(fields[4].trim());
                wo.setAltIDType(fields[5].trim());
                wo.setReason(fields[6].trim());
                try {
                    java.util.Date dob = dateformatYYYYMMDD.parse(fields[7].trim());
                    wo.setDob(dateformatYYYYMMDD.format(dob));
                } catch (Exception e) {
                    wo.setDob("");
                }
                //wo.setDob(fields[7].trim());
                wo.setRemark(fields[8].trim());
                // Set critical will map Y/1 to 1 N/2 to 2
                wo.setCriticalID(fields[9].trim());
                wo.setFileName(filename);
                wo.setLastMaintainDate(fields[10].trim());
                wo.setLastMaintainUser(fields[11].trim());
                wo.setWatchlistEntryID(wo.generateID(prefix, entryCount));
                wo.setLocation(entryCount);
                list.add(wo);
                entryCount++;
            }
        } // end of if

    } // end of while

    StringBuffer sb = new StringBuffer();
    sb.append("<Statement>DELETE FROM tbl_watch_list WHERE filename = '" + filename + "'</Statement>\n");
    java.util.Iterator<WatchlistEntryObject> iterator = list.iterator();
    while (iterator.hasNext()) {
        WatchlistEntryObject entry = iterator.next();
        sb.append(entry.getInsertSQL() + "\n");

        //System.out.println(entry.getInsertSQL());

    }
    return encloseInXml(sb.toString());



            }



    //return sb.toString();
}

public String encloseInXml(String sql) {
    StringBuffer sb = new StringBuffer();
    sb.append("<?xml version ='1.0' encoding = 'UTF-8' standalone = 'no'?>\n");
    sb.append("<VREMIT>\n");
    sb.append(sql);
    sb.append("</VREMIT>\n");
    return sb.toString();
    }
}
我正在考虑扫描字符串中的delimeter“D |”,以计算我可以解析的对象的最大行数,例如每10K一行,并将输出写入一个单独的文件,以避免“java.lang.OutOfMemoryError:java堆空间”错误

还有其他方法吗??如果您有任何建议,我将不胜感激


谢谢。

现在您正试图将整个输入文件读入内存(RAM)。这导致了你的错误


您不需要分配更多内存,而是需要读取文件的小段,为该小段生成XML,并将该XML附加到输出文件中。不要尝试同时将整个文件保存在内存中。

尝试使用LineNumberReader:

LineNumberReader lineReader = new LineNumberReader(new FileReader(fileName));
运行循环以读取每一行:

String data = lineReader.readLine();
读取每一行并处理它,然后写入OutputStream,希望这能有所帮助

干杯

您可以这样做:

StringBuffer sb = new StringBuffer();
sb.append("<Statement>DELETE FROM tbl_watch_list WHERE filename = '" + filename + "'</Statement>\n");
java.util.Iterator<WatchlistEntryObject> iterator = list.iterator();
while (iterator.hasNext()) {
    WatchlistEntryObject entry = iterator.next();
    sb.append(entry.getInsertSQL() + "\n");

    //System.out.println(entry.getInsertSQL());

}
return encloseInXml(sb.toString()); 
}

public String encloseInXml(String sql) {
  StringBuffer sb = new StringBuffer();
  sb.append("<?xml version ='1.0' encoding = 'UTF-8' standalone = 'no'?>\n");
  sb.append("<VREMIT>\n");
  sb.append(sql);
  sb.append("</VREMIT>\n");
  return sb.toString();
  }
}
StringBuffer sb=new StringBuffer();
sb.追加(“从tbl_监视列表中删除,其中文件名='”+filename+“\n”);
java.util.Iterator迭代器=list.Iterator();
while(iterator.hasNext()){
WatchlistEntryObject条目=迭代器.next();
sb.append(entry.getInsertSQL()+“\n”);
//System.out.println(entry.getInsertSQL());
}
返回encloseInXml(sb.toString());
}
公共字符串encloseInXml(字符串sql){
StringBuffer sb=新的StringBuffer();
某人附加(“\n”);
某人附加(“\n”);
sb.append(sql);
某人附加(“\n”);
使某人返回字符串();
}
}
因此,可以在StringBuilder中收集sql语句。 然后将其中的字符串传递给encloseInXml()。 在这里,您再次将相同的数据写入StringBuilder,并返回该数据的toString()。 此时,在内存中有2到4次包含SQL语句的字符串


为什么不直接写入文件?

将输入流式传输到输出。您不需要在内存中保留超过1个line/xml元素,我知道,但是读写是由另一个使用OracleWebLogic的类触发的。它将自动读取放置在指定文件夹中的整个文件,并将文件的全部内容解析到此类。考虑到这一点,是否仍有可能避免内存错误?我不熟悉oracle weblogic。我会找到一种方法将这个大文件分解成多个文件,或者找到另一种处理方法,或者(我不建议这样做)增加程序堆大小。防止大文件内存错误的唯一方法是分块处理,或增加内存。别无选择。如果他至少将xml流写入一个文件,而不是一个stringbuilder,这可能会有所帮助。@Ingo-right,这就是我在问题中的建议。也许问题被编辑了,但我没有看到对stringbuilder的大量写入?看看Parser类的下半部分-他这样做:
encloseInXml(sb.toString())
只是将其写入另一个stringbuilder并返回toString(),所以他在内存中至少有4次输出。
String data = lineReader.readLine();
StringBuffer sb = new StringBuffer();
sb.append("<Statement>DELETE FROM tbl_watch_list WHERE filename = '" + filename + "'</Statement>\n");
java.util.Iterator<WatchlistEntryObject> iterator = list.iterator();
while (iterator.hasNext()) {
    WatchlistEntryObject entry = iterator.next();
    sb.append(entry.getInsertSQL() + "\n");

    //System.out.println(entry.getInsertSQL());

}
return encloseInXml(sb.toString()); 
}

public String encloseInXml(String sql) {
  StringBuffer sb = new StringBuffer();
  sb.append("<?xml version ='1.0' encoding = 'UTF-8' standalone = 'no'?>\n");
  sb.append("<VREMIT>\n");
  sb.append(sql);
  sb.append("</VREMIT>\n");
  return sb.toString();
  }
}