我有一個文件從中讀取數據。 該文件中的所有文本都存儲在一個字符串變量(一個非常大的變量)中。 然後在我的應用程序的另一部分,我想遍歷這個字符串並逐步提取有用的信息(解析字符串)。如何處理大字符串和有限內存
與此同時,我的內存變滿,OutOfMemory異常讓我無法進一步處理。 我認爲從文件中讀取輸入流時直接處理數據會更好。但爲了組織的目的,我想將字符串傳遞給我的應用程序中的另一部分。
我應該怎麼做才能防止內存溢出?
我有一個文件從中讀取數據。 該文件中的所有文本都存儲在一個字符串變量(一個非常大的變量)中。 然後在我的應用程序的另一部分,我想遍歷這個字符串並逐步提取有用的信息(解析字符串)。如何處理大字符串和有限內存
與此同時,我的內存變滿,OutOfMemory異常讓我無法進一步處理。 我認爲從文件中讀取輸入流時直接處理數據會更好。但爲了組織的目的,我想將字符串傳遞給我的應用程序中的另一部分。
我應該怎麼做才能防止內存溢出?
您應該使用BufferedInputReader而不是將其全部存儲到一個大字符串中。
如果你想要解析的東西恰好在同一行上,那麼StringTokenizer會很好地工作,否則你必須設計一種方法來讀取你想從文件中解析出來的語句,然後將StringTokenizer應用到每個聲明。
如果您可以稍微放鬆您的需求,您可以實施由您的文件支持的java.lang.CharSequence。
支持CharSequence many places in the JDK(一個字符串是一個CharSequence)。所以這是基於Reader的實現的一個很好的選擇。
您必須檢查處理大量數據的算法。您必須逐個處理這些數據,或者使用隨機文件訪問而不將數據存儲在內存中。例如,你可以使用StringTokenizer或StreamTokenizer作爲@Zombies。 您可以看到解析器 - 詞法分析器技術:當解析器解析某個表達式時,它會要求詞法分析器讀取下一個lexem(令牌),但不會一次讀取整個輸入流。
其他人建議您一次讀取和處理文件的某些部分。如果可能的話,其中一種方法會更好。
但是,如果這是不可能的,並且您能夠將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的未來版本可能會改變這一點(雖然不太可能)。
難道你不能用一個讀者(例如BufferedReader)來逐個解析文件嗎? – 2010-01-27 16:09:43