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

时间:2015-05-06 13:36:18

标签: c# string file text system.io.file

我在文本文件中搜索字符串(也包括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;

但是他们中的哪一个(或者你的另一个?)的内存效率更高?

3 个答案:

答案 0 :(得分:3)

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

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

答案 1 :(得分:2)

我也更喜欢接受的答案。也许我在这里微观化了一些东西,但你已经要求一种记忆效率高的方法。另外请考虑您正在搜索的文字也可能包含新行字符,例如'\r''\n'"\r\n",理论上大文件可能包含一行,否定ReadLines的好处1}}。

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

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 examplesurrogate pairs

答案 2 :(得分:1)

我认为你的解决方案都是一样的。请阅读MSDN:https://msdn.microsoft.com/en-us/library/dd383503%28v=vs.110%29.aspx

它说:&#34; ReadLines和ReadAllLines方法的不同之处如下:当您使用ReadLines时,您可以在返回整个集合之前开始枚举字符串集合&#34;

同一篇文章还建议ReadLines应与LINQ to Objects一起使用。