读取文本文件并以内存有效的方式搜索字符串(并在找到时中止)

read a text file and search for string in memory efficient way (and abort when found)

我正在文本文件中搜索字符串(也包括 XML)。这是我首先想到的:

using (StreamReader sr = File.OpenText(fileName))
{
    string s = String.Empty;
    while ((s = sr.ReadLine()) != null)
    {
        if (s.Contains("mySpecialString"))
            return true;
    }
}

return false;

我想逐行阅读以尽量减少使用的 RAM 量。找到字符串后,它应该中止操作。我不按 XML 处理它的原因是因为它必须被解析,并且还会根据需要消耗更多内存。

另一个简单的实现是

bool found = File.ReadAllText(path).Contains("mySpecialString") ? true : false;

但这会将整个文件读入内存,这不是我想要的。另一方面,它可能会提高性能。

另一个就是这个

foreach (string line in File.ReadLines(path))
{
    if (line.Contains("mySpecialString"))
    {
        return true;
    }
}
return false;

但是其中哪一个(或您的另一个?)内存效率更高?

您可以使用带有 File.ReadLines 的查询,因此它只读取需要的行数以满足您的查询。 Any() 方法将在遇到包含您的字符串的行时停止。

return File.ReadLines(fileName).Any(line => line.Contains("mySpecialString"));

我认为您的两种解决方案都是相同的。阅读 MSDN:https://msdn.microsoft.com/en-us/library/dd383503%28v=vs.110%29.aspx

上面写着:"The ReadLines and ReadAllLines methods differ as follows: When you use ReadLines, you can start enumerating the collection of strings before the whole collection is returned"

同一篇文章还建议将 ReadLines 与 LINQ to Objects 结合使用。

我也更喜欢接受的答案。也许我在这里对事情进行了微观优化,但您已经要求一种内存有效的方法。还要考虑到您正在搜索的文本也可能包含换行符,如 '\r''\n'"\r\n",并且大文件理论上可能包含一行,这会抵消 [= 的好处15=]。

所以你可以使用这个方法:

public static bool FileContainsString(string path, string str, bool caseSensitive = true)
{
     if(String.IsNullOrEmpty(str))
        return false;

    using (var stream = new StreamReader(path))
    while (!stream.EndOfStream)
    {
        bool stringFound = true;
        for (int i = 0; i < str.Length; i++)
        {
            char strChar = caseSensitive ? str[i] : Char.ToUpperInvariant(str[i]);
            char fileChar = caseSensitive ? (char)stream.Read() : Char.ToUpperInvariant((char)stream.Read());
            if (strChar != fileChar)
            {
                stringFound = false;
                break; // break for-loop, start again with first character at next position
            }
        }
        if (stringFound) 
            return true;
    }
    return false;
}

bool containsString = FileContainsString(path, "mySpecialString", false); // ignore case if desired

请注意,这可能是最有效的方法,并且隐藏在一个同样可读的方法中。但它有一个缺点,实现文化敏感比较是不可行的,因为它查看单个字符而不是子字符串。

因此,您必须记住一些边缘情况,您可以在这些情况下 运行 解决问题,例如 famous turkish i example or surrogate pairs