读取文本文件时出现OutOfMemoryError

时间:2013-08-26 17:32:09

标签: java groovy

我需要在工作时解析csv文件。文件中的每一行都不是很长,只有几百个字符。我使用以下代码将文件读入内存。

def lines = []
new File( fileName ).eachLine { line -> lines.add( line ) }

当行数为10,000时,代码工作正常。但是,当我将行数增加到100,000。我收到了这个错误:

java.lang.OutOfMemoryError: Java heap space

对于10,000行,文件大小约为7 MB,100,000行为约70 MB。那么,你怎么解决这个问题呢?我知道增加堆大小是一种解决方法。但还有其他解决方案吗?提前谢谢。

2 个答案:

答案 0 :(得分:1)

def lines = []

在groovy中,这会创建一个大小为0的ArrayList<E>,而不会预先分配内部Object[]

添加项目时,如果达到容量,则会创建新的ArrayList。列表越大,重新分配新列表以容纳新条目所花费的时间就越多。我怀疑这是你的内存问题发生的地方,因为虽然我不确定ArrayList如何分配一个新的列表,如果你为一个相对较小的数据集获得OOM,那就是我首先看的地方。对于100,000个条目,当您从空ArrayList开始时,您创建一个大约29次(assuming expansion factor of 1.5)的新列表。

如果您对列表需要的大小有一个大概的了解,只需设置初始容量,这样做可以避免所有重新分配的废话;看看是否有效:

def lines = new ArrayList<String>(100000)

答案 1 :(得分:0)

假设您可能尝试将CS​​V文件放在数据库中,您可以执行以下操作。关键的常规功能是 splitEachLine(yourDelimiter)并使用闭包中的fields数组。

import groovy.sql.*

def sql = Sql.newInstance("jdbc:oracle:thin:@localhost:1521:ORCL",
    "scott", "tiger", "oracle.jdbc.driver.OracleDriver")

//define a variable that matches a table definition (jdbc dataset
def student = sql.dataSet("TEMP_DATA");
//now iterate over the csv file splitting each line on commas and load the into table.
new File("C:/temp/file.csv").splitEachLine(","){ fields ->
//insert each column we have into the temp table.
 student.add(
        STUDENT_ID:fields[0],
        FIRST_NAME:fields[1],
        LAST_NAME:fields[2]
    )
}
//yes the magic has happened the data is now in the staging table TEMP_DATA.
println "Number of Records  " + sql.firstRow("Select count(*) from TEMP_DATA")