Java 内存不足,无法处理大型文本文件并将其写回xml
我是java编程新手,现在在处理大型文本文件方面遇到了问题。我正在编写代码来处理整个文件的字符串,将其解析为一个类,然后将其转换为xml。挑战在于我只能处理少于70K行的输出;如果我的内存超过800K,它将抛出一个错误“java.lang.OutOfMemoryError:java堆空间”。这是我的示例文件和代码 示例文件1Java 内存不足,无法处理大型文本文件并将其写回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
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("&", "&");
line = line.replace("'", "''");
line = line.replace(">", ">");
line = line.replace("<", "<");
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();
}
}