2010-01-27 31 views
6

我有一個文件從中讀取數據。 該文件中的所有文本都存儲在一個字符串變量(一個非常大的變量)中。 然後在我的應用程序的另一部分,我想遍歷這個字符串並逐步提取有用的信息(解析字符串)。如何處理大字符串和有限內存

與此同時,我的內存變滿,OutOfMemory異常讓我無法進一步處理。 我認爲從文件中讀取輸入流時直接處理數據會更好。但爲了組織的目的,我想將字符串傳遞給我的應用程序中的另一部分。

我應該怎麼做才能防止內存溢出?

+0

難道你不能用一個讀者(例如BufferedReader)來逐個解析文件嗎? – 2010-01-27 16:09:43

回答

7

您應該使用BufferedInputReader而不是將其全部存儲到一個大字符串中。

如果你想要解析的東西恰好在同一行上,那麼StringTokenizer會很好地工作,否則你必須設計一種方法來讀取你想從文件中解析出來的語句,然後將StringTokenizer應用到每個聲明。

+0

+1。安東尼:總體思路是你通過CURSORS(就像數據庫)。它們可以是文本情況下的讀者,字節情況下的流,項序列中的迭代器等。您可以將一種類型轉換爲另一種類型(將序列中的每個項目(例如文件中的一行轉換爲某個域對象),但是應用程序的一個區域提供給另一個區域的是遊標,因此它是一個處理消耗一次只輸入一個步驟,不會導致讀取文件的知識或您在中間實施的任何轉換。 – helios 2010-01-28 08:31:51

+0

您提供的「BufferedInputReader」和「StringTokenizer」的鏈接不可用。 – Root 2016-06-17 08:41:34

6

如果您可以稍微放鬆您的需求,您可以實施由您的文件支持的java.lang.CharSequence

支持CharSequence many places in the JDK(一個字符串是一個CharSequence)。所以這是基於Reader的實現的一個很好的選擇。

1

您必須檢查處理大量數據的算法。您必須逐個處理這些數據,或者使用隨機文件訪問而不將數據存儲在內存中。例如,你可以使用StringTokenizer或StreamTokenizer作爲@Zombies。 您可以看到解析器 - 詞法分析器技術:當解析器解析某個表達式時,它會要求詞法分析器讀取下一個lexem(令牌),但不會一次讀取整個輸入流。

4

其他人建議您一次讀取和處理文件的某些部分。如果可能的話,其中一種方法會更好。

但是,如果這是不可能的,並且您能夠將String最初加載到內存中,但是您稍後解析了此字符串會產生問題,您可能可以使用子字符串。在Java中,子字符串映射在原始的char數組的頂部,並且僅佔用基地Object的內存,然後是開始和長度的int指針。

所以,當你發現你想要單獨保留字符串的一部分,使用類似:

String piece = largeString.substring(foundStart, foundEnd); 

如果你不是這個或代碼,內部做到這一點,那麼內存的使用將顯着增加:

new String(largeString.substring(foundStart, foundEnd)); 

請注意,您必須謹慎使用String.substring()這個原因。你可以有一個非常大的字符串,你需要一個子字符串,然後放棄你對原始字符串的引用。問題是子字符串仍然引用原始大型數組。直到子字符串也被移除後,GC纔會釋放它。在這種情況下,實際使用new String(...)以確保未使用的大數組將被GC丟棄(這是您應該使用new String(...)的少數情況之一)。

另一種技術,如果你期望有很多小字符串,並且這些字符串可能具有相同的值,但來自外部源(如文件),則在創建新字符串後使用.intern()

注意:這取決於String的實現,您實際上不應該知道這一點,但實際上對於大型應用程序,有時您必須依賴這些知識。請注意,Java的未來版本可能會改變這一點(雖然不太可能)。