2013-08-26 180 views
0

我需要解析工作中的csv文件。文件中的每一行都不是很長,只有幾百個字符。我使用下面的代碼將文件讀入內存。讀取文本文件時出現OutOfMemoryError

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。那麼,你會如何解決這個問題呢?我知道增加堆大小是一種解決方法。但是還有其他解決方案嗎?先謝謝你。

+3

您可以處理每一行而不是將所有行保存在內存中,或者出於某種原因,您真的需要將它們放在內存中? – gurbieta

+0

我不熟悉groovy,但每次從csv文件讀取一行時都會創建新對象,它是'new File(fileName).eachLine {line - > lines.add(line)}''創建新對象嗎?我個人用python做了同樣的事情,從來沒有得到任何錯誤。 – Prateek

+1

您正在將每一行添加到內存中的列表中。列表中的'lines'變胖並導致OOM – Will

回答

1
def lines = [] 

在常規,這產生了一個與ArrayList<E>大小0並且沒有內部Object[]的預分配。

添加項目時,如果達到容量,將創建新的ArrayList。列表越大,重新分配新列表以容納新條目的時間就越多。我懷疑這是你的內存問題發生的地方,因爲儘管我不確定ArrayList是如何分配一個新列表的,但是如果你爲一個相對較小的數據集獲得OOM,那麼我首先會看到它。對於100,000條目,當從空的ArrayList開始時,創建一個新列表大致29次(assuming expansion factor of 1.5)。

如果你有一個大致的想法,那就是設置初始容量,這樣做可以避免所有重新分配的廢話;看看這是否工作:

def lines = new ArrayList<String>(100000) 
0

假設你可能試圖將CSV文件放在數據庫中,你可以這樣做。關鍵的groovy功能是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") 
相關問題