2013-06-03 226 views
1

我必須閱讀一個大的文本文件(大約5兆字節)。閱讀重文本文件

爲了閱讀這個文件,我使用了BufferedReader(),但它會導致內存泄漏和堆增長,有沒有其他選擇來優化我的代碼?

  StringBuffer sb = new StringBuffer(); 
      BufferedReader reader = new BufferedReader(new FileReader(vCache)); 
      String line = null; 

      while ((line = reader.readLine()) != null) 
      { 
       sb.append(line); 
      } 
+0

你的日誌很貴(字符串concact)並且可能是你的內存泄漏... – Johannes

+0

你爲什麼要讀一個5 MB的文件?請解釋這背後的要求? – krishnakumarp

+0

@krishnakumarp嗯,我需要獲取我所有的Web服務器數據庫行,將其保存在文本文件中,以json格式解析它,最後將其逐一插入到本地數據庫中。 – iSun

回答

0

您正在解析JSON。

如果輸入文件存在,您可以通過刪除美化(例如縮進,換行符等)來縮小輸入文件。

你也可以嘗試一個直接從流中讀取的解析器,希望它不需要一次緩衝所有內容。例如,Android提供了JsonReader,它允許您解析流並自己控制數據結構,這意味着您可以使用更多的內存高效結構,並且它也不會緩衝整個流。不幸的是,它被添加到API級別11中,所以向後兼容可能是一個問題。

一種替代方法是,如果頂級對象是一個數組,可以將它拆分成幾個較小的數組,也許在不同的文件中,分別解析它們併合並子數組。如果基礎對象具有相似的結構,則可以在合併之前將它們轉換爲Java對象,這將具有更緊湊的內存結構。

+0

感謝弗拉德,是的,我試圖解析json,你能給我一個關於從流中讀取json的例子嗎? – iSun

+0

嘗試使用Jackson JSON解析器,http://wiki.fasterxml.com/JacksonHome,您可以直接從'inputStream'解析JSON – reidzeibel

1

嘗試使用InputStream代替BufferedReader

try { 
    InputStream is = new FileInputStream(vCache); 
    byte[] b = new byte[is.available()]; 
    is.read(b); 
    String text = new String(b); 
} 
1

我猜你正在讀本地文件。在這種情況下,你可能會更好整個文件讀入一個字節數組,然後轉換爲字符串:

InputStream is = new FileInputStream(vCache); 
byte[] buffer = new byte[is.available()]; 
is.read(buffer); 
is.close(); 
jsonContent = new String(buffer, "UTF-8"); 

然而,你仍可以通過讀取這麼大的文件中的Android到內存中邀請的問題。我想說,如果你需要閱讀一個5 MB的json文件,你可能沒有正確地構建你的應用程序。

1

默認bufferSize使用BufferedRedaer8KB,但由於您正在逐行讀取積累將更多。爲了改善這一點,你可以使用:

BufferedReader(Reader in, int sz) < - 使用sz較小值說4KB

read(char[] cbuf) < - 約束cbuf尺寸爲讀者大小

close() <的 - 無論記憶被holded者通過閱讀器實例現在可以被GCed

現在你的代碼StringBuffer sb保存所有的行在完整的文件內容,甚至如果需要的內存(〜fileSize)對JVM不可用,則進行上述更改後,您將再次遇到OOM問題。我不確定這是否與你一樣,否則以上應該會改善本地內存的高峯。

0

您的代碼...正如所寫...讀取行並將其累積在StringBuilder中。事實上,你積累的線是一種內存泄漏的形式。

,以防止泄漏的最好辦法是改變你的應用程序是這樣工作的:

BufferedReader reader = new BufferedReader(new FileReader(vCache)); 
    String line = null; 
    while ((line = reader.readLine()) != null) { 
     process(line); 
    } 

換句話說,不積累線路在內存中。在閱讀時處理它們,然後丟棄它們。


如果你的處理是這樣的,你必須積聚在內存中的行,那麼你將得到更好的內存使用情況,如果您分配StringBuilder這樣的:

StringBuilder sb = new StringBuilder(fileSizeInCharacters); 

這將避免需要重新分配,這可能(在最壞的情況下)需要文件大小的3倍(以字符爲單位)。

但是,您遲早會遇到同樣的問題。在內存中累積文件內容不會縮放。


您的評論表明這確實是一個JSON處理問題。下面是問答&一個上的流JSON處理的話題:

流API的想法是,你並不需要的JSON「對象」轉換成IN-內存樹結構代表整個事物。

0

發送JSON,使每行對應一個完整的db行和格式良好的json。這樣你就不必一起處理整個文件。

//StringBuffer sb = new StringBuffer(); 
BufferedReader reader = new BufferedReader(new FileReader(vCache)); 
String line = null; 

while ((line = reader.readLine()) != null) { 
    //Parse JSON 
    //Insert into local SQLite DB. 
}