2010-01-27 73 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的未来版本可能会改变这一点(虽然不太可能)。