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

本文关键字:巨大 文件 拆分 单词 一个 | 更新日期: 2023-09-27 18:01:13

如何从文本文件中读取一个很长的字符串,然后对其进行处理(拆分为单词(?

我尝试了StreamReader.ReadLine()方法,但得到了OutOfMemory异常。显然,我的队伍很长。这是我读取文件的代码:

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<string> 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 ;
}