如何将一个巨大的文件分成单词?

如何从文本文件中读取一个非常长的字符串,然后处理它(拆分成单词)?

我尝试了StreamReader.ReadLine()方法,但是我得到了OutOfMemoryexception。 显然,我的线条非常长。 这是我读取文件的代码:

 using (var streamReader = File.OpenText(_filePath)) { int lineNumber = 1; string currentString = String.Empty; while ((currentString = streamReader.ReadLine()) != null) { ProcessString(currentString, lineNumber); Console.WriteLine("Line {0}", lineNumber); lineNumber++; } } 

以及将行分为单词的代码:

 var wordPattern = @"\w+"; var matchCollection = Regex.Matches(text, wordPattern); var words = (from Match word in matchCollection select word.Value.ToLowerInvariant()).ToList(); 

您可以通过char读取,随意构建单词,使用yield使其延迟,这样您就不必立即读取整个文件:

 private static IEnumerable ReadWords(string filename) { using (var reader = new StreamReader(filename)) { var builder = new StringBuilder(); while (!reader.EndOfStream) { char c = (char)reader.Read(); // Mimics regex /w/ - almost. if (char.IsLetterOrDigit(c) || c == '_') { builder.Append(c); } else { if (builder.Length > 0) { yield return builder.ToString(); builder.Clear(); } } } yield return builder.ToString(); } } 

代码按字符读取文件,当遇到非单词字符时,它将yield return到那时为止构建的单词(仅适用于第一个非字母字符)。 该代码使用StringBuilder来构建单词字符串。

Char.IsLetterOrDigit()行为与字符的正则表达式字符w ,但下划线(以及其他)也属于后一类。 如果您的输入包含您希望包含的更多字符,则必须更改if()

将其切成比特大小的部分。 所以,而不是试图读取4gb,我认为这是一个页面的大小,尝试阅读8 500mb块,这应该有所帮助。

垃圾收集可能是一种解决方案。 我不确定这是问题来源。 但如果是这种情况,简单的GC.Collect通常效率不高,并且出于性能原因,只有在真正需要时才应该调用它。 当可用内存过低(低于作为过程参数提供的阈值)时,请尝试以下过程调用垃圾。

 int charReadSinceLastMemCheck = 0 ; using (var streamReader = File.OpenText(_filePath)) { int lineNumber = 1; string currentString = String.Empty; while ((currentString = streamReader.ReadLine()) != null) { ProcessString(currentString, lineNumber); Console.WriteLine("Line {0}", lineNumber); lineNumber++; totalRead+=currentString.Length ; if (charReadSinceLastMemCheck>1000000) { // Check memory left every Mb read, and collect garbage if required CollectGarbage(100) ; charReadSinceLastMemCheck=0 ; } } } internal static void CollectGarbage(int SizeToAllocateInMo) { long [,] TheArray ; try { TheArray =new long[SizeToAllocateInMo,125000]; }low function catch { TheArray=null ; GC.Collect() ; GC.WaitForPendingFinalizers() ; GC.Collect() ; } TheArray=null ; }