我需要在工作时解析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。那么,你怎么解决这个问题呢?我知道增加堆大小是一种解决方法。但还有其他解决方案吗?提前谢谢。
答案 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)
假设您可能尝试将CSV文件放在数据库中,您可以执行以下操作。关键的常规功能是 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")